Variable Zeitleiste - blödes Min-Sek-System

Für allgemeine Fragen zur Programmierung mit PureBasic.
Sven
Beiträge: 374
Registriert: 23.09.2004 12:01

Variable Zeitleiste - blödes Min-Sek-System

Beitrag von Sven »

Ich versuche eine variable Zeitleiste wie zum Beispiel in Audacity verwendet zu programmieren.

Dabei sollen die Minuten und Sekunden als sinnvolle Werte dargestellt werden, z.B. wie hier:

Bild
Bild
Bild
Bild

Mein Vorgehen bisher: Zerlegen der Zeitdauer in Abschnitte, Zerlegen der Abschnitte in Mantisse und Exponent, Mantisse anpassen und wieder zusammenrechnen:

Code: Alles auswählen

Procedure.s TimeString(time.l)  ;Zeit msec in String mmm:ss.hsec
  If time >= 0  ;wenn gültige Zeit
    time = time / 10  ;Zeit aus msec
    text.s = Right("00" + Str(time % 100), 2)  ;hsec
    time = time / 100
    text = Right("00" + Str(time % 60), 2) + "." + text  ;sec
    time = time / 60
    text = Str(time) + ":" + text  ;min
    ProcedureReturn text
  Else
    ProcedureReturn ""
  EndIf
EndProcedure

tmin.l = 515 * 1000  ;Startzeit Leiste
tmax.l = 525 * 1000  ;Endzeit Leiste
  Debug Str(tmin) + " - " + TimeString(tmin)
  Debug Str(tmax) + " - " + TimeString(tmax) 
xw.f = 800  ;Breite in Pixel

td.l = tmax - tmin  ;Differenz
  Debug td
kn.l = xw / 100  ;Anzahl Abschnitte
  Debug kn
te.f = Pow(10, Int(Log10(100 * td / xw)))  ;Exponent
  Debug te
tm.f = Pow(10, Mod(Log10(100 * td / xw), 1))  ;Mantisse
  Debug tm
If tm < 2  ;Mantisse anpassen
  tn = 2
ElseIf tm < 5
  tn = 5
Else
  tn = 10
EndIf
  Debug tn
ts.f = tn * te  ;Zeitabschnitt
  Debug Str(ts) + " - " + TimeString(ts)
t1 = tmin - Mod(tmin, ts) + ts  ;Startabschnitt
  Debug Str(t1) + " - " + TimeString(t1)
For k.l = 0 To kn
  tp.l = k * ts + t1
  If tp > tmax  ;kann größer werden durch Streckung
    Break
  EndIf
  xp.l = xw * (tp - tmin) / (tmax - tmin)
  Debug Str(xp) + " - " + Str(tp) + " - " + TimeString(tp)
Next
Das funktioniert soweit auch und gibt sinnvolle Werte:
515000 - 8:35.00 (min)
525000 - 8:45.00 (max)
...
80 - 516000 - 8:36.00
240 - 518000 - 8:38.00
400 - 520000 - 8:40.00
560 - 522000 - 8:42.00
720 - 524000 - 8:44.00
Aber überschreite ich die 60 Sekunden, bekomme ich mitunter unschöne Werte:
515000 - 8:35.00 (min)
815000 - 13:35.00 (max)
...
93 - 550000 - 9:10.00
227 - 600000 - 10:00.00
360 - 650000 - 10:50.00
493 - 700000 - 11:40.00
627 - 750000 - 12:30.00
760 - 800000 - 13:20.00
Hier wäre 9:00, 10:00, 11:00 besser. Das liegt wahrscheinlich daran, daß mein Algo dekadisch rundet und dabei die 60 Sekunden-Abschnitte nicht berücksichtig werden.

Wie bekomme ich es hin, daß hier wie in den Beispielen aus Audacity auf 60 Sekunden gerundet wird? Oder auf sinnvolle Bruchteile. Also 0, 15, 30, 45... Sekunden, aber nicht auf 10, 25, 40, 55...

Ich hab da einen Knoten im Kopf, weil ich da auch mit Fallunterscheidungen irgendwie nicht weiterkomme. Eine andere Idee wäre noch eine Lookup-Table, in der die zulässigen Werte drinstehen.

Die Randbedingungen sind:
- Zeitauflösung t = 1msec
- kleinste Zeitdifferenz td = 1sec = 1000msec
- größte Zeitdifferenz td = 180min = 10.800.000msec
- kleinste Leistenbreite xw = 200 Pixel
- größte Leistenbreite xw = 4000 Pixel
- kleinste dargestellte Auflösung 10msec = 1/100stel Sekunde

Dabei sollen auch Extreme angezeigt werden können, z.B. tmin = 179:59, tmax = 180:00 als 179:59.00, 179:59.20, 179:59.40, 179:59.60, 179:59.80...

Die nächste Herausforderung ist dann, nicht nur die Zahlen, sondern auch die dazwischenliegenden Ticks sinnvoll zu verteilen... ;-)
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7035
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Variable Zeitleiste - blödes Min-Sek-System

Beitrag von STARGÅTE »

Ich hatte mal eine Achseneinteilungsfunktion geschrieben, allerdings auch dekadisch.

Hier im Zeitraum würde ich lieber Art Liste von möglichen Step-Werten (in Sekunden) erstellen:
1, 2, 5, 10, 15, 20, 30, 60, 90, 120, 180, 300, 600, ...

Dann nimmst du deine Zeitbreite (zB 67s) und prüftst nun nach und nach, wie viele Ticks es geben würde:
67/1, 67/2, 67/5 usw. und brichst dann ab, wenn es zB weniger als 10 Ticks gibt.

Das sind dann vllt viele If abfragen, aber rein "rechnerisch" gesehen, sind Pow() und Log() funktionen auch "Zeitfressend"
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Sven
Beiträge: 374
Registriert: 23.09.2004 12:01

Re: Variable Zeitleiste - blödes Min-Sek-System

Beitrag von Sven »

Ich habs mal versucht, es sind gar nicht so viele Abfragen wie ich dachte, weil das ja wieder schön expotentiell skaliert.

Und soweit ich es sehe, funktionert es wunderbar. Die Zwischenticks mache ich durch nochmalen Aufruf der Funktion mit kleinerer Ausgangsbreite xmin.

Allerdings sollte man tunlichst die Zeiten mit Quad definieren (unten noch falsch), sonst können einige Zwischenwerte überlaufen.

Code: Alles auswählen

Procedure.s TimeString(time.l)  ;Zeit msec in String mmm:ss.hsec
  If time >= 0  ;wenn gültige Zeit
    time = time / 10  ;Zeit aus msec
    text.s = Right("00" + Str(time % 100), 2)  ;hsec
    time = time / 100
    text = Right("00" + Str(time % 60), 2) + "." + text  ;sec
    time = time / 60
    text = Str(time) + ":" + text  ;min
    ProcedureReturn text
  Else
    ProcedureReturn ""
  EndIf
EndProcedure

tmin.l = 3012 * 1000
tmax.l = 8125 * 1000
  Debug Str(tmin) + " - " + TimeString(tmin)
  Debug Str(tmax) + " - " + TimeString(tmax)
  
  xw.f = 825
  xmin.f = 100  ;min. Pixel zwischen Zeiten

td.l = tmax - tmin  ;Differenz
Debug td
kn.l = xw / xmin  ;Anzahl Abschnitte
Debug kn

ts.l = xmin * td / xw

Select ts
  Case 0 To 10
    tn = 10
  Case 0 To 20
    tn = 20
  Case 0 To 50
    tn = 50
  Case 0 To 100
    tn = 100
  Case 0 To 200
    tn = 200
  Case 0 To 500
    tn = 500
  Case 0 To 1 * 1000  ;1sec
    tn = 1 * 1000
  Case 0 To 2 * 1000
    tn = 2 * 1000
  Case 0 To 5 * 1000
    tn = 5 * 1000
  Case 0 To 10 * 1000
    tn = 10 * 1000
  Case 0 To 15 * 1000
    tn = 15 * 1000
  Case 0 To 20 * 1000
    tn = 20 * 1000
  Case 0 To 30 * 1000
    tn = 30 * 1000
  Case 0 To 1 * 60 * 1000  ;1min
    tn = 1 * 60 * 1000
  Case 0 To 2 * 60 * 1000
    tn = 2 * 60 * 1000
  Case 0 To 5 * 60 * 1000
    tn = 5 * 60 * 1000
  Case 0 To 10 * 60 * 1000
    tn = 10 * 60 * 1000
  Case 0 To 15 * 60 * 1000
    tn = 15 * 60 * 1000
  Case 0 To 20 * 60 * 1000
    tn = 20 * 60 * 1000
  Case 0 To 30 * 60 * 1000
    tn = 30 * 60 * 1000
  Case 0 To 1 * 60 * 60 * 1000  ;1hour
    tn = 1 * 60 * 60 * 1000
  Case 0 To 2 * 60 * 60 * 1000
    tn = 2 * 60 * 60 * 1000
  Case 0 To 3 * 60 * 60 * 1000
    tn = 3 * 60 * 60 * 1000
  Default
    tn = 180 * 60 * 1000
EndSelect
    
Debug tn

t1 = tmin - Mod(tmin, tn) + tn  ;Startabschnitt
  Debug Str(t1) + " - " + TimeString(t1)

For k.l = 0 To kn
  tp.l = k * tn + t1
  If tp > tmax  ;kann größer werden durch Streckung
    Break
  EndIf
  xp.l = xw * (tp - tmin) / (tmax - tmin)
  Debug Str(xp) + " - " + Str(tp) + " - " + TimeString(tp)
Next
Antworten