Level-Anzeige von Player

Hi Zusammen
An einer Stelle komme ich nicht weiter. Ich möchte gern die Level - Anzeigen (Pegel) von Player 1 und 2 an meinen MIDI Controller senden, damit ich dort der Pegel mittels der LEDs angezeigt wird.
Ich denke mal der Ansatz :: levelinfo := Encoder.GetInputLevelInfo(eiPlayer); ist nicht der Richtige.
Hat jemand eine Idee?
Danke im Voraus
Gruß Tom

Puh, Level-Anzeige via MIDI, ich weiß nicht, ob das wirklich praktikabel ist.

ILevelInfo ist schon das richtige Interface. Allerdings nicht das vom Encoder, sondern das der Player - da kommt man ganz einfach per Typecast dran, hier im Beispiel für den ersten Player der ersten Playlist, also “Player A” in der Standardkonfiguration:

levelinfo := ILevelInfo(PlaybackControl(0).GetPlayer(0));

Zum Abfragen der Levels deklariert man eine Variable vom Typ “TLevelArray” und ruft “GetLevels” auf.

var
  levels: TLevelInfo;

begin
  levelinfo := ILevelInfo(PlaybackControl(0).GetPlayer(0));
  levelinfo.GetLevels(levels);
end.

Das Array hat danach die gleiche Länge wie die Anzahl Kanäle des aktuellen Elementes. Also 1 = mono, 2 = stereo, 0 = Player ist nicht geladen.

Die Werte selbst sind float und im Bereich 0 (Stille) bis 1 (Vollausschlag), wobei auch Werte >1 vorkommen können (“Übersteuerung”).

Es handelt sich dabei jeweils um das Maximum der Sample-Werte in einem Fenster der letzten 20 Millisekunden.

Der Wert sollte zunächst mit Hilfe der Funktion LinearToDB(linwert) in einen dB-Wert umgerechnet werden.

Achtung, dort ist noch keine Rücklaufzeit berechnet. DIN-Peakmeter verwenden eine Rücklaufzeit von 1,7 Sekunden je -20dB. Das heißt, wenn das Signal schlagartig von 0dB auf minus undendlich fällt, dann muss es 1,7 Sekunden später noch als -20dB angezeigt werden usw. - der Balken “wandert” langsam auf Null zurück, anstatt schlagartig zu fallen.

Für die Darstellung in einem DIN-artigen Pegelmeter gibt es dann noch folgende schöne Funktion:

function DBToScale(iDB: single; iOverhead: single): single; // Umkehrfunktion zu oben

Diese nimmt einen dB-Wert und berechnet daraus die Breite bzw. die Höhe des Peakmeter-Balkens. Die Skala ist nämlich üblicherweise weder ganz logarithmisch noch exakt linear. Zu übergeben ist der dB-Wert sowie der Overhead, also der positive dB-Wert, der die obere Grenze der Skala sein soll. Zurück kommt ein Wert 0…x, der die Breite des Balkens angibt, üblicherweise 0…1, aber auch hier können wieder Werte >1 vorkommen wenn das Signal übersteuert ist.

Diesen normierst du dann auf 127 und übergibst ihn an dein MIDI-Gerät.

Alles klar? :slight_smile:

Hi Torben

vielen lieben DANK. Es funktioniert!

Viele Grüße
Tom

Wenn du magst, poste doch gerne mal das komplette Script.

Mache ich gerne. Bei mir sieht es so jetzt aus:

procedure OnLoad;
begin
  levelinfoP1 := ILevelInfo(PlaybackControl(0).GetPlayer(0));
  levelinfoP2 := ILevelInfo(PlaybackControl(0).GetPlayer(1));
  EnableTimer(20);  
end;

procedure OnTimer;
var
  levelsP1: TLevelArray;
  levelsP2: TLevelArray;
  levelP1: single;
  levelP2: single;
begin
  levelinfoP1.GetLevels(levelsP1)
  levelinfoP2.GetLevels(levelsP2)
  if(length(levelsP1) >= 1) then
  begin
    levelP1 := DBToScale(1 - LinearToDB(levelsP1[0])) * 127.0;
    levelP2 := DBToScale(1 - LinearToDB(levelsP2[0])) * 127.0;
    MidiOut ( 1, 176, 96, trunc(levelP1));
    MidiOut ( 1, 176, 97, trunc(levelP2));
  end;
end;

Fein :slight_smile:

Das “DBToScale(1 - LinearToDB(…), …)” verstehe ich noch nicht. Willst du die Anzeige umdrehen? Eigentlich sollte doch “DBToScale(LinearToDB(…), …)” richtig sein, oder?

Und noch ein Hinweis: Den Check “length >= 1” musst du natürlich für beide Player getrennt machen. Sonst crashed dein Script, wenn in Player 1 eine Stereo- und in Player 2 eine Mono-Datei liegt.

Hi Torben

Den Check "length >= 1" musst du natürlich für beide Player getrennt machen.
Ups, das habe ich wohl übersehen. Stimmt. Danke für den Hinweis!
"DBToScale(1 - LinearToDB(..), ...)" verstehe ich noch nicht. Willst du die Anzeige umdrehen?
Nein, so ist sie aber bei mir korrekt. Wenn ich es nicht negiere, ist sie umgedreht.

Liebe Leute, nachdem ich nie weiß, ob ich alte Threads entstauben darf oder nicht probiere ich es mal, weil mein Anliegen hier eigentlich sehr gut passt…
Ich hatte letzte Woche auch die Idee mir den aktuellen Pegel anzeigen zu lassen. Nur möchte ich mir den Pegel in eine Textdatei speichern (um diese dann später in einem selbstgeschrieben Programm wieder auszulesen). So weit so gut, ich habe das Script von hier also versucht bei mir mit kleinen Änderungen zum laufen zu bringen, aber ich bekomme bei folgenden Code immer einen Null Pointer Error.

var
  levelinfoP1, levelinfoP2: ILevelInfo;
  StringList: TStringList;
procedure OnLoad;
begin
  levelinfoP1 := ILevelInfo(PlaybackControl(0).GetPlayer(0));
  levelinfoP2 := ILevelInfo(PlaybackControl(0).GetPlayer(1));
  EnableTimer(20);  
end;
procedure OnTimer;
var
  levelsP1, levelsP2: TLevelArray;
  levelP1,levelP2: integer;
begin
    try
      levelinfoP1.GetLevels(levelsP1)
    except
    finally
  end;
    try
      levelinfoP2.GetLevels(levelsP2)
    except
    finally
  end;

if(length(levelsP1) >= 1) then
  begin
    levelP1 := trunc(levelsP1[0] * 100);
    StringList.Add(IntToStr(levelP1));
  end;
if(length(levelsP2) >= 1) then
  begin
    levelP2 := trunc(levelsP2[0] * 100);
    StringList.Add(IntToStr(levelP2));
  end;
try
      StringList := TStringList.Create;
      StringList.Add(IntToStr(levelP1));
      StringList.Add(IntToStr(levelP2));
      StringList.SaveToFile('C:\ProgramData\mAirList\6.3\scripts\Pegel.txt');
      StringList.Free;
    except
    finally
  end;
end;

Das Script an sich wird erkannt, sobald ich jedoch die Zeile

levelP1 := trunc(levelsP1[0] * 100);

einfüge beginnt mAirList im Systemprotokoll den Error anzuzeigen und auch Kommandos (Maus, Midi-Mischpult) werden nicht mehr umgesetzt. Den Befehl

DBToScale(1 - LinearToDB(levelsP1[0])) * 127.0;

konnte ich nicht ausprobieren, da hier der Fehler " Invalid Number of Parameters" erscheint.

Vielleicht kann mir ja jemand von euch wissenden weiterhelfen, warum dieser Error angezeigt wird und wie ich den (Denk-)Fehler beseitige.
Sonnige Grüße aus dem heißen Wien,
und danke schon mal im voraus, Patrick

Also ich weiß ja nicht, immer wenn ich bei einem Problem um Hilfe bitte komme ich kurz darauf selber auf die Lösung, wobei mir @Tondose auch per PN helfen konnte. Hier also die Fehlerursache:
Im Teil

if(length(levelsP1) >= 1) then
  begin
    levelP1 := trunc(levelsP1[0] * 100);
    StringList.Add(IntToStr(levelP1));
  end;
if(length(levelsP2) >= 1) then
  begin
    levelP2 := trunc(levelsP2[0] * 100);
    StringList.Add(IntToStr(levelP2));
  end;

habe ich nun die Stringlist.Add Befehle rausgenommen, wozu ja auch 2x im Script, wird ja schließlich später im try-Block in eine Stringlist geschrieben. Nun funktioniert das Script so wie gewollt. Manchmal ist das Ziel doch so nahe :see_no_evil:
Patrick

2 Likes

Und wie sieht das mit der Latenz aus? Ich kann mir gerade schwer vorstellen, dass das sinnvoll nutzbar ist.

Bin ich echt neugierig drauf.

Zur Latenz: Kann ich dir noch nicht sagen.
Ist aktuell auch mehr eine Spielerei, unter anderem auch um zu sehen, was mir mAirList und Scripts alles möglich ist.
Ob das ganze sinnvoll ist? Kann ich auch noch nicht sagen. Ich hab mir ein eigenes Programm geschrieben, das gewisse Daten anzeigt, die per Script weitergegeben werden. Aktuell nur Titel - Interpret. Da möchte ich mal die Pegel auch anzeigen lassen und schauen, ob es für mich wertvoll ist, oder eben nicht.
Kann sein, dass ich mein Projekt dann auch wieder über den Haufen werfen werde. Wie gesagt aktuell bin ich etwas am ausprobieren, was sich alles mit der Software “anstellen” lässt.