Jetzt noch besser: Backtiming durch stummes Abfahren

Die Backtimingprozedur, die ich vor einiger Zeit öffentlich gemacht habe, funktioniert so nur für den Assist-Modus. Möchte man einen Mixdown einer gevoicetrackten Produktion erstellen, so braucht es eine etwas andere Vorgehensweise; erst recht, wenn die Ausspielung live im Automatikbetrieb erfolgen soll.

Für diese beiden Fälle ist das folgende Skript geeignet.

Was passiert also beim „Fahren auf Zeit“? Für Quereinsteiger: Ein (in der Regel instrumentaler, nicht ausgeblendeter) Schlußtitel wird zunächst stumm (ohne dessen Regler aufzuziehen) zu einer Zeit abgefahren, daß er beispielsweise genau zum Stundenende fertig ist. Um den Übergang zu kaschieren, wird der letzte Titel abmoderiert (Fachjargon: „auf die Naht sprechen“), unter der Abmoderation langsam etwas aufgeblendet (Fachjargon: „mit Musik anblasen“. Wirklich. Hab’ ich nicht erfunden!) und zum Ende der Moderation dann voll aufgeblendet. Damit endet der Schlußtitel auf den Punkt.

Das ganze passiert jetzt automatisch. Wir benötigen dazu zunächst

  • eine Schaltfläche (Statischer Text), deren Name und ausgebender Befehl im Kopf des Skripts selbst festgelegt werden kann.

Damit schalten wir die Backtimingautomatik frei. Ich gehe davon aus, daß in der Playlist vor dem betreffenden Fixtimeelement (welches den Zeitpunkt für das geplante Ende definiert) zunächst als letztes Element der einzublendende Schlußtitel und als vorletztes die Abmoderation eingestellt ist. Soviel Ordnung muß sein. Das Fixtimeelement darf auch Audio enthalten und mittels Anchor an die Fixzeit gepinnt sein.

Jetzt brauchen wir noch

  • ein Steuerelement beliebigen (aber eindeutigen) Namens (kann im Skript festgelegt werden) ohne Audio (Länge 0:00), um der Automatik zu sagen, daß tatsächlich ein Backtiming stattfinden soll. Dieses Element muß direkt vor dem Fixtimeelement eingestellt werden.

Das Skript stellt bei jedem Start eines Players zunächst fest, ob die Voraussetzungen (Abmod, Schlußtitel, Steuerelement vorhanden) gegeben sind. Falls ja, wird die Abmoderation daraufhin geprüft, ob ein Ramp 1-Marker vorhanden ist. Dies ist der (manuell zu setzende) Zeitpunkt, an welchem die Musikblase starten soll. Ist diese Marke nicht vorhanden, so wird sie selbsttätig an den Beginn der Modulation der Abmod gesetzt.

Gleiches erfolgt entsprechend am Modulationsende, wenn kein Outro-Marker für den Beginn der finalen Aufblende gesetzt ist.

Legt man Wert auf die automatische Bestimmung, sollte in der Konfiguration Auto-Cue aktiviert und auf vernünftige Werte (um –40 dB) gesetzt sein. (Konfiguration > Verschiedenes > Auto-Cue > Cue In automatisch bestimmen, bzw. Cue Out …)

Die betreffenden Elemente werden dann farblich markiert, damit es schöner ist. Anschließend werden für den Schlußtitel Startzeitpunkt und Hüllkurvenpunkte gesetzt. Die Dynamik der Musikblase (Pegel, Länge der Blenden) läßt sich im Kopf des Skripts frei definieren.

Ist die Playlist für einen Mixdown vorgesehen, so wird als harte Fixzeit die geplante Dauer der Produktion (also z. B. 00:59:55) gesetzt.

Das Skript führt nur die Berechnung der Längen durch. Die Titel sollten zeitlich schon in die Stunde (bzw. in den betreffenden Zeitraum) passen, das ist bei einer Voicetracking-Vorproduktion in der Regel auch der Fall. Bei automatischer Playlistgenerierung muß der Betreiber respektive ein anderes Skript für die korrekte Anzahl der Elemente sorgen. Ist der verbleibende Rest des Schlußtitels nicht mindestens so lang wie die Abmoderation plus der Aufblende (d. h. es sind zuwenige oder zuviele Titel vorgesehen bzw. es stimmt die Basiszeit nicht, weil noch kein Player gestartet ist und sie nicht fortlaufend aktualisiert wird), erscheint eine Fehlermeldung.

Um einen reibungslosen Ablauf des Backtimings zu gewährleisten, sind mindestens drei Player erforderlich. Wer im Regelfall nur zwei Player definiert hat, kann, wenn das Backtiming an der kritischen Stelle ist, einen dritten Player zuschalten, der am Ende des Schlußtitels wieder weggenommen wird. Wählt man diese Option nicht, muß gewährleistet werden, daß sich der abzusagende und der Schlußtitel nicht überschneiden.

Ein kleiner Trost zum Schluß: Das alles klingt komplizierter als es tatsächlich ist. Hat man einmal den Bogen raus, funktioniert die Mimik tadellos. (Jedenfalls auf meinem System. Wahrscheinlich ist bei Euch alles ganz anders.)

Pünktliche Grüße

TSD


Ich wollte gerne das etwas längliche Skript als Anhang hochladen, aber das geht nicht, da die Endung .mls für den Hochlad gesperrt ist. Speziell in diesem Forum halte ich das nicht eben für zielführend. Also:


{ 

  +------------------------------------------------------------------------+
  |                                                                        |
  | Backtiming-Skript für Playout und Mixdown                              |
  |                                                                        |
  | Version 4.1, © 2019 Tondose (https://community.mairlist.com/u/tondose) |
  |                                                                        |
  +------------------------------------------------------------------------+


Voraussetzungen:

• Schaltfläche mit beliebigem Namen (festzulegen in den Einstellungen)
  als statischer Text.

• Schaltfläche gibt beliebigen Befehl (festzulegen in den Einstellungen).

• Fixtime-Element mit beliebiger harter Fixzeit, darf Audio enthalten.
  Für Mixdown Fixzeit von Dauer der Vorproduktion, z.B. 00:59:59.
  
• Steuerelement in Playlist der Länge 0'00" und beliebig festzulegendem Namen.

• Schlußmoderation kann mit Ramp1- und Outro-Marker zur Steuerung
  der Musikblase versehen werden.
  
  
Changelog:

V4.1
[*] Neuberechnung der Parameter bei jedem Playerstart
[+] Farbe der Elemente nach Reset bestimmbar
[+] Plausibilitätsprüfung für CueIn

V4.0:
[*] Code völlig umgestellt
[*] Neue Steuerung sowohl für Mixdown als auch Automatikausspielung
[+] Beliebiger Buttonname und -Befehl
[+] Fixtime-Element kann Audio enthalten 
[*] Auslösung des Backtimings durch Steuerelement mit beliebig
    festzulegendem Namen
[+] Automatische Cuemarken für Abmod bei Modulationsbeginn und -ende

V3.13:
[*] GetPlayerCount in procedure OnLoad verlegt
[-] Kunstpause beim Backtiming entfernt
[+] Auf Wunsch schreiende Fehlermeldungen
[+] OnUnload hinzugefügt
[+] CueIn des Schlußtitels wird beim Abschalten wiederhergestellt 
[+] Hüllkurvenpunkte des Schlußtitels werden beim Abschalten gelöscht
[*] TIMINGOFFSET greift sinnvoller ein
[-] irreführenden Titel geändert
[+] Changelog etabliert

V3.12:
[*] Plausibilitätsprüfung völlig neu geschrieben
[*] Code neu strukturiert

V3.11:
[*/+/-] Das will keiner wissen

V1.0:
[*] Erste Version

}


const                                                                           //Randbedingungen definieren

  STARTLEVEL = -50;          // Startpegel der Blase in dBr
  MODLEVEL = -12;            // Pegel der Blase in dBr (während Mod)
  FADEINDURATION = 3;        // Fade-In-Zeit in Sekunden (zur Einblendung unter Mod)
  FADEUPDURATION = 2;        // Fade-Up-Zeit in Sekunden (nach der Mod)
  FADEUPOFFSET = 1;          // Beginn der Aufblende bei AutoCue verfrühen
  TIMINGOFFSET = 0;          // Offset für Schlußtitel in Sekunden, negative Werte verkürzen
  
  SET3PLAYERS = true;        // Drei Player beim Backtiming verwenden
  
  POPUPERRORS = true;        // Fehlermeldungen hervorheben

  BTCAPTION = 'Backtiming';  // Titel des Steuerelements in Playlist
  BUTTONCMD = 'BACKTIMING';  // Befehl bei Klick auf Button
  BUTTONNAME = 'BUTTON.BACKTIMING'; // Buttonname für Fernsteuerung

  COLORON = '#00FF00';       // Buttonfarbe "ein"
  COLOROFF = '#AAAAAA';      // Buttonfarbe "aus"
  COLORALARM = '#FF0000';    // Buttonfarbe "Alarm"
  TEXTON = '#000000';        // Textfarbe "ein"
  TEXTOFF = '#666666';       // Textfarbe "aus"
  TEXTALARM = '#FFFFFF';     // Textfarbe "Alarm"

  COLORFIXITEM = $0000FF;    // Farbe des Fixtime-Elementes
  COLORENDTITLE = $00FF00;   // Farbe des Schlußtitels
  COLORENDMOD = $FF0000;     // Farbe der Abmoderation
  COLORRESET = $EEEEEE;      // Farbe nach Reset der Elemente



{ ---------------------------------------------------------------------------- }

var                                                                             // Deklaration der Variablen
  PlzBacktime, BacktimeError: boolean;
  PlayerCount, FixIndex: integer;
  StartTime, EndTime, EndModStartTime, CueStartTime: TDateTime;
  EndTitleDuration, EndTitleCue, OrgCueIn: TTimeValue;
  EndMod, EndTitle, FixItem, BTItem: IPlaylistItem;
  
procedure OnLoad;                                                               // Initialisierung
begin
  PlzBacktime := false;
  BacktimeError := false;
  PlayerCount := CurrentPlaylist.GetPlayerCount;                                // Playeranzahl feststellen
  ExecuteCommand(BUTTONNAME + ' BACKGROUNDCOLOR ' + COLOROFF);
  ExecuteCommand(BUTTONNAME + ' FONTCOLOR ' + TEXTOFF);
end; 

procedure ButtonAlarm;                                                          // Button "Warnung"
begin
  ExecuteCommand(BUTTONNAME + ' BACKGROUNDCOLOR ' + COLORALARM);
  ExecuteCommand(BUTTONNAME + ' FONTCOLOR ' + TEXTALARM);
end;

procedure ButtonOn;                                                             // Button "einschalten"
begin
  ExecuteCommand(BUTTONNAME + ' BACKGROUNDCOLOR ' + COLORON);
  ExecuteCommand(BUTTONNAME + ' FONTCOLOR ' + TEXTON);
end;

procedure ButtonOff;                                                            // Button "ausschalten"
begin
  ExecuteCommand(BUTTONNAME + ' BACKGROUNDCOLOR ' + COLOROFF);
  ExecuteCommand(BUTTONNAME + ' FONTCOLOR ' + TEXTOFF);
  EndTitle.SetColor(COLORRESET);
  EndMod.SetColor(COLORRESET);
  FixItem.SetColor(COLORRESET);
end;

procedure BTError(Message: string);                                             // Routine für Fehlermeldung
begin
  BacktimeError := true;
  ButtonAlarm;
  SystemLog('Backtimingfehler: ' + Message);
  if POPUPERRORS then
    ShowMessage(Message);
end;

procedure FindBacktimingItems;                                                  // Vorbereitungen für Backtiming
begin 
  if CurrentPlaylist.GetNextFixedTime > 0 then begin
    FixItem := CurrentPlaylist.GetNextFixedTimeItem;                            // Nächstes Fixtime-Element suchen
    FixIndex := CurrentPlaylist.IndexOf(FixItem);                               // Index feststellenm
    BTItem := CurrentPlaylist.GetItem(FixIndex - 1);                            // Steuerelement
    if (BTItem.GetTitle = BTCAPTION) AND (BTItem.GetDuration = 0) then begin    // Prüfen, ob gültig
      BacktimeError := false;                                                   // Wenn ja, Backtiming freigeben
    end
    else begin
      BacktimeError := true;
    end;
    EndTitle := CurrentPlaylist.GetItem(FixIndex - 2);                          // Schlußtitel …
    EndMod := CurrentPlaylist.GetItem(FixIndex - 3);                            // … und Abmoderation bestimmen
    OrgCueIn := EndTitle.GetCuePosition(ptCueIn);                               // Ursprüngliches CueIn festhalten
    if (EndTitle.GetDuration = 0) OR (EndMod.GetDuration = 0) then begin
      BTError ('Elemente zum Backtimen müssen eine Spieldauer haben.');          // Fehler, wenn keine Spieldauer
    end;
  end;
end;

procedure ClearBacktiming(Title: IPlaylistItem);
begin
  Title.SetCuePosition(ptCueIn, OrgCueIn);                                      // Schlußtitel auf urspr. CueIn zurücksetzen …
  Title.GetVolumeEnvelope.Clear;                                                // … und Hüllkurvenpunkte löschen
end;
  
procedure Backtiming;                                                           // Backtimingprozedur
var
   TempCuePosition: TTimeValue;
begin                                   
  if (FixItem.GetDuration > 0) AND (EndTitle.GetCuePosition(ptStartNext) > 0)
    then EndTitleDuration := EndTitle.GetAudibleDuration 
      - (EndTitle.GetAudibleDuration - EndTitle.GetCuePosition(ptStartNext))    // Wenn Fixtime-Element Dauer hat, auf StartNext cuen.
  else
    EndTitleDuration := EndTitle.GetAudibleDuration;                            // Länge des Schlußtitels feststellen
  EndTitle.GetVolumeEnvelope.Clear;                                             // Sicherheitshalber Hüllkurvenpunkte löschen
  EndTitle.SetColor(COLORENDTITLE);                                             // Schön farbig machen
  EndMod.SetColor(COLORENDMOD);
  FixItem.SetColor(COLORFIXITEM); 
  EndTime := frac(CurrentPlaylist.GetMetadata(FixIndex).
    GetStartTime(sttCalculated));                                               // Endzeit feststellen (Startzeit des Fixtime-Elementes)
  EndModStartTime := CurrentPlaylist.
    GetMetadata(CurrentPlaylist.IndexOf(EndMod)).GetStartTime(sttCalculated);   // Startzeit der Endmod feststellen
  if EndMod.GetCuePosition(ptRamp1) = 0 then begin                              // Feststellen, ob EndMod Ramp1-Marker besitzt, falls nicht, …
    TempCuePosition := EndMod.GetCuePosition(ptCueIn);                          // … ursprüngliches CueIn merken, …
    CurrentPlaylist.BeginRead;                                                  // … Playlist sperren, …
    try
      EndMod.AutoSearchPosition(ptCueIn);                                       // … per AutoCue Modulationsbeginn feststellen, …
    finally
      CurrentPlaylist.EndRead;                                                  // … Playlist freigeben, …
    end;
    EndMod.SetCuePosition(ptRamp1, EndMod.GetCuePosition(ptCueIn));             // … CueIn in Ramp1 umwidmen und …
    EndMod.SetCuePosition(ptCueIn, TempCuePosition);                            // … ursprüngliches CueIn wiederherstellen
  end;
  if EndMod.GetCuePosition(ptOutro) = 0 then begin                              // Feststellen, ob EndMod Outro-Marker-Marker besitzt, falls nicht, …
    TempCuePosition := EndMod.GetCuePosition(ptCueOut);                         // … ursprüngliches CueOut merken, …
    CurrentPlaylist.BeginRead;                                                  // … Playlist sperren, …
    try
      EndMod.AutoSearchPosition(ptCueOut);                                       // … per AutoCue Modulationsende feststellen, …
    finally
      CurrentPlaylist.EndRead;                                                  // … Playlist freigeben, …
    end;
    EndMod.SetCuePosition(ptOutro, EndMod.GetCuePosition(ptCueOut) 
      - FADEUPOFFSET);                                                          // … CueOut in Outro umwidmen, Ofset berücksichtigen und …
    EndMod.SetCuePosition(ptCueOut, TempCuePosition);                           // … ursprüngliches CueOut wiederherstellen
  end;
  CueStartTime := EndModStartTime + (EndMod.GetCuePosition(ptRamp1) 
    - EndMod.GetCuePosition(ptCueIn)) / 86400;                                  // Startzeit der Aufblende
  EndTitleCue := EndTitleDuration - (EndTime - frac(CueStartTime)) * 86400;     // Länge des Schlußtitels setzen
  if (EndTitleCue - TIMINGOFFSET >= EndTitle.GetAudibleDuration -
    EndMod.GetAudibleDuration - FADEUPDURATION) OR
    (EndTitleCue - TIMINGOFFSET < 0) then                                       // Prüfen, ob CueIn mit Titellänge korrespondiert
    BTError('Fehler beim Backtiming: Ausreichend/zuviele Elemente? '
    + 'Korrekte Basiszeit?');
  EndMod.SetCuePosition(ptStartNext, EndMod.GetCuePosition(ptRamp1) + 0.1);     // Start des Schlußtitels setzen
  if EndTitle.GetCuePosition(ptCueIn) - TIMINGOFFSET >= 0 then                  // Prüfen, ob Offset zu groß
    EndTitle.SetCuePosition(ptCueIn, EndTitleCue - TIMINGOFFSET);               // CueIn des Schlußtitels setzen, ggf. Offset berücksichtigen 
  EndTitle.GetVolumeEnvelope.AddPoint
    (0, STARTLEVEL, 'FadeInBegin');                                             // Hüllkurvenpunkt (HkP) am Fileanfang
  EndTitle.GetVolumeEnvelope.AddPoint          
    (EndTitleCue, STARTLEVEL, 'FadeInStart');                                   // HkP unten zu Beginn der Blase
  EndTitle.GetVolumeEnvelope.AddPoint
    (EndTitleCue + FADEINDURATION, MODLEVEL, 'ModLevelStart');                  // HkP oben zu Beginn der Blase
  EndTitle.GetVolumeEnvelope.AddPoint
    (EndTitleCue + Endmod.GetCuePosition(ptOutro) 
    - EndMod.GetCuePosition(ptRamp1), MODLEVEL, 'FadeUpStart');                 // HkP unten zum Mod-Ende
  EndTitle.GetVolumeEnvelope.AddPoint
    (EndTitleCue + EndMod.GetCuePosition(ptOutro) 
    - EndMod.GetCuePosition(ptRamp1) + FADEUPDURATION, 0, 'FadeUpEnd');         // HkP oben zum Mod-Ende
end; 

procedure OnExecuteCommand(Command: string);
begin
  if (Command = BUTTONCMD) AND NOT PlzBacktime then begin                       // Backtiming für Mixdown einschalten
    PlzBacktime := true;                                                        // Zustand merken
    ButtonOn;                                                                   // Knopf leuchten lassen
    if CurrentPlaylist.GetCount < 4 then                                        // Mecker, wenn zu wenig Fleisch
      BTError('Zu wenige Elemente in der Playlist')
    else
      FindBacktimingItems;
    if NOT BacktimeError then                                                   // Wenn alles karl, …
      Backtiming;                                                               // … los geht's!
  end
  else if (Command = BUTTONCMD) AND PlzBacktime then begin                      // Backtiming ausschalten
    PlzBacktime := false;
    BacktimeError := false; 
    ButtonOff;
    ClearBacktiming(EndTitle);                                                  // Schlußtitel auf urspr. CueIn zurücksetzen und HkP löschen
    if SET3PLAYERS then
      CurrentPlaylist.SetPlayerCount(PlayerCount);                              // Playeranzahl zurücksetzen
  end;
  
  if Command = 'SET2PLAYERS' then
    CurrentPlaylist.SetPlayerCount(2);                                          // Hilfskommando zum Zurücksetzen der Playeranzahl
end;

procedure OnPlayerStateChange(PlaylistIndex: integer; PlayerIndex: integer; 
  OldState: TPlayerState; NewState: TPlayerState; Item: IPlaylistItem);
begin
  if NewState = psPlaying then begin                                            // Bei Playerstart …
    if (Item <> EndTitle) AND (Item <> EndMod) then begin
      if CurrentPlaybackControl.GetAutomation then begin                        // … und Automatikbetrieb …
        ClearBacktiming(EndTitle);                                              // … Backtiming neu berechnen, …
        FindBacktimingItems;                                                    // … Vorbereitungen treffen …
        if NOT BacktimeError then                                                   
          Backtiming;                                                           // … und ggf. Backtiming anstoßen
      end;
    end; 
    if SET3PLAYERS AND (CurrentPlaylist.GetPlayerCount < 3)                     // Wenn Abmod beginnt, …
      AND (Item = EndMod) then begin
      CurrentPlaylist.SetPlayerCount(3);                                        // … ggf. zusätzlichen Player einsetzen …
    end;
  end
  else if (Item = EndTitle) AND (NewState = psStopped) then                     // … und nach Schlußtitel …
    if SET3PLAYERS then 
      CurrentPlaylist.SetPlayerCount(PlayerCount);                              // … wieder zurücksetzen
end;

procedure OnUnload;                                                             // Bei Programmstop …
begin
  if PlzBacktime then
    ClearBacktiming(EndTitle);                                                  // Schlußtitel auf urspr. CueIn zurücksetzen und HkP löschen
  if SET3PLAYERS then
    CurrentPlaylist.SetPlayerCount(PlayerCount);                                // … wieder zurücksetzen
end;


begin 
end.                                                                            // Punkt.
2 Likes

Danke, TSD,

kann ich nur bestätigen. Hat sich bei mir in der Praxis schon vielfach bewährt.

LG, Martin

2 Likes

Danke, mein lieber Betatester!

Unterstützte Grüße

TSD

1 Like

Danke für die Anregung. Der Administrator hat *.mls soeben als erlaubte Datei-Erweiterung hinzugefügt.
Du darfst es gerne testen, wenn du magst.

2 Likes