Voicetracking Script

Based upon the original code by Christoph, I have modified it to allow for full voicetracking within your Playlist. All info is contained in the script - Simply ensure that your “Artist” fields say Voicetrack. Any audio file over 90 seconds will be treated as a song and will be matched-up with the preceeding Voicetrack (subject to the song having a Ramp).

The only bug I’ve found is that a song with a CueIn set will crash the vocal. Have fun.

[code]// mAirTracking - Script to ease Voicetracking with mAirList
// written by Christoph Rothe and released under GPL
//
// v1.0 - initial Release
// v1.01- Bugfix
// v1.1 - modifications by Charlie Davy
// Voicetracks now play into songs - or rather, ANY audio track over 90 seconds

// Preparation
// All Voicetracks MUST contain “Voicetrack” in the Artist field. Or modify the settings below to suit your configuration
// Audio files over 90 seconds will be treated as a song. Change this if you wish.

// KNOWN BUG: A Voicetrack playing into a song with a Cue Point set will crash the vocal!
// ie: 10 second Voictrack, 5 second Ramp but a 1s CueIn will mean the Voicetrack finishes at 6 seconds into the file :frowning:

var
i: integer;
voicetrack: integer;
song: integer;

begin
voicetrack:=-1;
song:=-1;
for i := 0 to CurrentPlaylist.GetCount - 1 do
begin
if CurrentPlaylist.GetItem(i).GetArtist = ‘Voicetrack’ then
begin

// Enable this for SystemLog
// SystemLog(‘Item ‘+inttostr(i)+’ is a Voicetrack’);

voicetrack:=i;
end else
if CurrentPlaylist.GetItem(i).GetDuration > 900000000 then
begin

// Enable this for SystemLog
//SystemLog('Item ‘+inttostr(i)+’ is a song by '+CurrentPlaylist.GetItem(i).GetArtist);

song:=i;

CurrentPlaylist.GetItem(voicetrack).GetCuePosition(ptStartNext).SetValue(CurrentPlaylist.GetItem(voicetrack).GetDuration-CurrentPlaylist.GetItem(song).GetCuePosition(ptRamp1).GetValue);

SystemLog(‘Success!’);

end else
begin
if (song >= 0) and (voicetrack >= 0) then
begin

end;
song:=-1;
voicetrack:=-1;
end;
end;
end.[/code]

This would be a good script to have enabled on your “Actions” button :slight_smile:

VERY cute script, Charlie: nice one! 8)

My first suggestion—which depends on how you have tagged your tracks, obviously!—would be to subract the equivalent of 0.4s from the line which sets the StartNext point in the voicetracks. This makes it sound a tad more ‘natural’ IMHO. :slight_smile: Not necessary in my case because I set all Ramps 0.4s back from where they actually occur, to allow for presenter reaction time in Assist mode ;).

Also, you don’t seem to cater for multiple Ramp points (though my eyesight isn’t as good as it was :wink: )? In most case, if two or three ramps are set, it’s the ‘last’ one (2 or 3) that is the actual start of the vocals proper. So you miight need to adapt the code to check all three Ramps’ values in turn (per item!) and use the largest of the three values as your ‘subtract from duration of voicetrack’ number.

BFN
CAD

Hi Cad,
The Ramp issue is a fair point, and I had thought about it - but didn’t want to faff around more with the basic working script! To be fair, I didn’t do too much to the original script, just trimmed it down and adjusted the selection criteria (artist vs comment). It’s not perfect as I say - but fairly easy to tweak. I’m finally learning more and more of the script language, so hopefully I’ll be posting more answers than questions in time :slight_smile:

I would like to just step onto my soapbox for a sec about the use of the script - It’s really designed for “operator assisted automation”, ie: It really needs a tech-op to sit there and ride the faders in order to ensure that levels are balanced. I don’t agree that music should be normalized to 80% or anything like that - 99% is my preference (the peak, not the average!). Same for idents/voicetracks - although they get a fair amount of processing via Adobe Audition giving them some “punch”. Set your levels at the mixer, that’s what it’s there for. Don’t let the processor do all the work :slight_smile:

Remember… Crap in = Crap out (no matter what the playlist policy!)

I should cut down on this brand of coffee.

By the way, mAirList 3.0 will support arbitrary volume envelopes on all items. Although possibly without a fancy GUI editor at first. This should come very handy for voice tracking.

OK folks, I’m no Pascal expert (!) but here is a re-write which cures the CueIn bug and caters for occasions where the ramp time is longer than the voicetrack (think about it: you need to start the song ‘in sync’ with the voicetrack in this case!). It also lower-cases the test string for the ‘voicetrack’ artist name to cater for All OPtions and vaRiants of it ;), AND checks all three ramp points and uses the largest (= ‘latest’) value set.

No doubt there will be some syntax errors in the code below, which Torben will hopefully correct. :wink: It is completely untested, just adapted from the original.

Enjoy!

CODE REMOVED BY CAD: SEE NEW VERSION IN THIS THREAD!


BFN
CAD

OK chaps, sorry for the false start above :-[.

I took my previously posted code and gave it a fairly thorough ‘bash’ here.

Some further points arose during testing, all of which I have now fixed. 8)

[ul][li]Items were numbered from zero (not 1) in SystemLog entries.[/li]
[li]‘Duration’ of voicetrack did not account for CueIn, FadeOut, CueOut points in voicetrack.[/li][/ul]

I think and hope you will find that this version does everything required. I tested it here with some ‘year’ jingles (adjusting Artist accordingly!) as ‘voicetracks,’ each preceding a music track, and I have to say I was pretty impressed with the results! The music tracks I tried had a variety of of cue points set (and NOT set), so I’m pretty confident it should handle just about anything.

Well done to both Cristoph and Charlie for the concept: all I’ve done is tidy amd tighten up the code so that it should work in all circumstances except while the Playlist is actually playing something right now (!).

CODE REMOVED BY CAD: SEE NEW VERSION IN THIS THREAD!

I hope everyone else finds this ‘new, improved!’ version useful.

BFN
CAD

Nice one - I did a bit of tweaking my script and have something which resembles yours now.

My ramp code is a tad different:

ramp := CurrentPlaylist.GetItem(song).GetCuePosition(ptRamp3).GetValue; if ramp = 0 then ramp := CurrentPlaylist.GetItem(song).GetCuePosition(ptRamp2).GetValue; if ramp = 0 then ramp := CurrentPlaylist.GetItem(song).GetCuePosition(ptRamp1).GetValue; ramp := ramp - CurrentPlaylist.GetItem(song).GetCuePosition(ptCueIn).GetValue;

However, both our scripts fail to process a Playlist if there is no Voicetrack at the start :frowning:

Our two versions of ramp code achieve the same result, though. Two slightly different means to the same end!

I’ve fixed mine now: sincere thanks for pointing out that minor error! The corrected version is below, with one extra check which I’ve highlighted:

// Amend the voicetrack ONLY if it is the IMMEDIATELY preceding item
if (voicetrack = i - 1) and (voicetrack > -1) then


The new check stops the code trying to amend the (non-existent!) item above the top item in the Playlist >cough<. My excuse is that I (re-)wrote and tested the whole thing in about 10 minutes. And I still loathe Pascal syntax and prefer good old VB (but not that VB.NET abomination!).

[code]// mAirVoiceList - Script to ease Voicetracking with mAirList
// re-written by Cad Delworth
//
// Based on original code by Christoph Rothe and released under GPL,
// with modifications by Charlie Davy
//
// v1.0 - initial release

// Preparation:
// The Playlist to be processed must be the CURRENT (selected) Playlist.
//
// All Voicetracks MUST contain “Voicetrack” as the Artist field in MP3 file (or MMD or MLP file).
// Audio files of 90+ seconds are treated as songs.
// Change the CONSTs below if you wish to change one or both of these.

const
SONG_MIN_LENGTH = 900000000;
VOICETRACK_ARTIST = ‘voicetrack’;

var
i: integer;
voicetrack: integer;
duration: LongInt;
cuein: LongInt;
ramp: LongInt;
ramptest: LongInt;
fadeout: LongInt;
cueout: LongInt;

begin

voicetrack := -1;

SystemLog(‘mAirVoiceList is processing the current playlist…’);

for i := 0 to CurrentPlaylist.GetCount - 1 do
begin

if AnsiLowerCase(Trim(CurrentPlaylist.GetItem(i).GetArtist)) = VOICETRACK_ARTIST then
begin

// Enable next line to write a SystemLog entry
// SystemLog(‘Item ’ + inttostr(i + 1) + ’ is a Voicetrack’);

  voicetrack := i;
end
else if CurrentPlaylist.GetItem(i).GetDuration >= SONG_MIN_LENGTH then
begin

// Enable next line to write a SystemLog entry
// SystemLog('Item ’ + inttostr(i + 1) + ’ is a song by ’ + CurrentPlaylist.GetItem(i).GetArtist);

// Amend the voicetrack ONLY if it is the IMMEDIATELY preceding item
if (voicetrack = i - 1) and (voicetrack > -1) then
begin

// Enable next line to write a SystemLog entry
// SystemLog('Setting StartNext point in Voicetrack Item ’ + inttostr(voicetrack + 1));

// Calculate maximum Ramp cue point value of song, less CueIn value of song
ramp := CurrentPlaylist.GetItem(i).GetCuePosition(ptRamp1).GetValue;

    ramptest := CurrentPlaylist.GetItem(i).GetCuePosition(ptRamp2).GetValue;
    if ramptest > ramp then
      ramp := ramptest;

    ramptest := CurrentPlaylist.GetItem(i).GetCuePosition(ptRamp3).GetValue;
    if ramptest > ramp then 
      ramp := ramptest;

    ramp := ramp - CurrentPlaylist.GetItem(i).GetCuePosition(ptCueIn).GetValue;

// Calculate ‘effective’ duration of voicetrack
// ‘Effective’ EOF is the least of non-zero FadeOut, CueOut, and the full duration
duration := CurrentPlaylist.GetItem(voicetrack).GetDuration;
cuein := CurrentPlaylist.GetItem(voicetrack).GetCuePosition(ptCueIn).GetValue;
fadeout := CurrentPlaylist.GetItem(voicetrack).GetCuePosition(ptFadeOut).GetValue;
cueout := CurrentPlaylist.GetItem(voicetrack).GetCuePosition(ptCueOut).GetValue;

    if (cueout > 0) and (cueout < duration) then
      duration := cueout;
    if (fadeout > 0) and (fadeout < duration) then
      duration := fadeout;

// Reduce ‘effective’ duration by any non-zero CueIn length
if cuein > 0 then
duration := duration - cuein;

// Set StartNext of voicetrack item to ‘effective’ duration less ramp length,
// BUT set StartNext to ONE if ramp is longer than voicetrack ‘effective’ duration
// (forces next item to start ‘in sync’ with voicetrack, instead of AFTER the voicetrack EOF)
if ramp <= duration then
CurrentPlaylist.GetItem(voicetrack).GetCuePosition(ptStartNext).SetValue(duration - ramp)
else
CurrentPlaylist.GetItem(voicetrack).GetCuePosition(ptStartNext).SetValue(1);

  end

end  // of song duration > min length... loop

end // of playlist for… loop

SystemLog(‘mAirVoiceList has ended successfully’);

end.
[/code]

BFN
Cad Delworth CEng MBCS CITP

Cad,
This works rather well, although I did make one minor change - when setting the StartNext point to ensure that a song with a long ramp starts in-sync with a short voicetrack, the value of “1” didn’t seem to work, so I set it to the following:

    if ramp <= duration then
      CurrentPlaylist.GetItem(voicetrack).GetCuePosition(ptStartNext).SetValue(duration - ramp)
    else
      CurrentPlaylist.GetItem(voicetrack).GetCuePosition(ptStartNext).SetValue([b]5000000[/b]);

This is 500ms, which seems to work fine for me.

EDIT: I’ve also decided that it may be better (for me) to have any type of audio available as a “voicetrack”, so I’ve renamed them as Overlays. I have now set the EndType as “x” to designate this item as available for mixing over songs.

Use the following new lines of code:

OVERLAY = ‘x’;
if AnsiLowerCase(Trim(CurrentPlaylist.GetItem(i).GetEndType)) = OVERLAY then

Just another way of doing things :slight_smile:

This is turning into quite a programming discussion, isn’t it? :slight_smile:

OK, a few points and thoughts I’ve had since yesterday.

  1. The ramp code: There is nothing built in to mAirList to stop anyone setting up Ramps in the ‘wrong’ order (for example Ramp1=39.5s and Ramp2=4.7s), right? I know that wouldn’t make much sense when the item hits a Player, but my point is that it IS possible to find a track like that while processing a Playlist. Therefore I prefer my version, because yours assumes that Ramp points are always in order and would fail with my example above; my code would still correctly use the ‘latest’ (i.e. largest) defined Ramp value.

  2. What you call the constant (OVERLAY, VOICETRACK_ARTIST) doesn’t really matter; but I would tactfully suggest you change it to OVERLAY_END_TYPE, as a reminder that the value is a comparison for the EndType property of an item. Nice idea, though: and an excellent ‘lateral’ use for the EndType field! But why use x rather than o (for Overlay)?!!
    (BOOM BOOM!)

  3. I also suggest that you change your 5000000 (aka 500mS) value into a constant named something like START_NEXT_IN_SYNC. This makes it MUCH easier to find and change later, should you ever need to tweak it; and also reminds you immediately of what this constant is for (especially when you come back to this code in nine months and have forgotten how it works! ;)).

General programming note: Moving all ‘magic numbers,’ strings to search for, etc. to the top of the program and turning them into named constants (technically they are called ‘manifest constants’) is always a good idea and is almost always the best way to go. Doing this means that everything is in the one place and easy to find and change, and also eliminates the chance of typos if you need to use any of the ‘constant’ values twice in the same code. :wink:

I think that all we need now is the ability to generate and handle user-defined dialog boxes in mAirListScript (don’t faint, Torben!). Wouldn’t it be good to have a dialog with radio buttons allowing you to select the field you want to use to identify ‘overlays/voicetracks,’ and a TextBox where you type in the value you want to look for? For example: EndType and x, Artist and voicetrack, etc., etc.

BFN
CAD

OK, rather than post the code yet again :wink: … I’ve attached a ZIPfile which contains a commented and uncommented copy of a final version of this voicetracking/overlaying script.

I’ve added a few more features, including a count of the amended files which shows up in the system log at the end of the script, and a check that the current playlist is in ASSIST and contains at least two items.

This final version uses Charlie’s excellent idea of using the Ending property of a Playlist item to mark ‘voicetrack’ files, and the script looks for an Ending value the letter o (upper or lower case) to identify a voicetrack.

Enjoy!

PS: Could Torben please either post a link to this topic in the German Script forum, or just add a post there with the ZIPfile attached? Thanks in advance.

BFN
CAD


SetOverlayPoints.zip (3.37 KB)

Brilliant, works a treat. Well done, Cad.

I relented and set-up mAirList with a “special” Player and let it run through a few items with the “special” Player set +6dB and I have to admit, it’s a really good way of basic voicetracking during automation. I envisage this going further once Torben impliments the features - An item can be tagged as an “Overlay” and this then reduces other items in that Playlist by a pre-set level (say 10dB) and restores the volume after. I think only 3 settings would be required for that: FadeDownTime, FadeUptime and FadeLevel.

Actually, I think that is technically possible now - By setting a script to run when an Overlay starts (to reduce the volume of sound device x) and one to restore the volume when it ends. Quite a long way around, but in theory I 'spose it’d work :-\

Many thanks for that (but then, I am a programmer by profession!).

I had a bit of angst earlier, prompted by tagging some tracks with two ramp points. At present, the script will use the latest (i.e. ‘largest’) ramp point value to work out the overlay point, which will usually be what you want. But you may sometimes wish to use the earliest (i.e. ‘smallest’) ramp point: it depends how you tag your files!

An example is the Weather Girls Xmas record (Bring Me A Man This Christmas). You’ll probably pop a Ramp point in at the start of the singing proper, but there is something like 25s of spoken banter and preamble. At present, the script will trample on that preamble.

What do you reckon, Charlie? Calculate everything based on the ‘first’ Ramp, or the ‘last’ Ramp (as at present)?

BFN
CAD

Yeah, that’s an issue to mull-over… There are plenty of songs where (using my ramp ethos) you may only want to talk-up Ramp1 - Using your Xmas-themed example, the Waitresses and “Christmas Wrapping” is a typical song where you may wish to talk up that guitar solo, and hit the bit where the drums and main melody kick-in (21sec in) rather than 39sec to the main vocal point. It’s really down to how you want it to sound generally.

In the future, a visual segue editor would aid this kind of thing - If you had 3 Ramps set, you could see each one as a coloured block (just like the ProgressBar does it) and adjust accordingly. Only a human knows how each segue will sound, the script just follows the timings :wink:

I suppose, you could put a further IF/ELSE statement in that if the voicetrack is within a few seconds of Ramp1/2, then to use that ?

I’ve thought of some better ways than that 8), based on your comments.

Firstly, a new manifest constant named DEFAULT_RAMP with the allowed values ‘first’ or ‘last’. DEFAULT_RAMP := ‘last’; means (by default) use the ‘latest’ song ramp point which exists, and you would change this to DEFAULT_RAMP := ‘first’; to (again by default) use the ‘earliest’ song ramp point which exists.

Why do I say ‘by default,’ you ask? Simple! :wink: If for any specific voicetrack, you want it to ‘talk up to’ for example Ramp 2, you change its Ending property from o to o2 (or o1 for Ramp1 or o3 for Ramp3) ;D. All of which will allow you to easily override the default setup for a specific voicetrack file without messing around inside the script.

I’m still working out the ramifications of how to handle it when (say) o2 is specified, but there isn’t a Ramp2 specified for the following song. I reckon the best way would be to punt out a SystemLog warning message anyway, and either:

[ul][li]use the current default of earliest/latest ramp to set the StartNext in the voicetrack, OR[/li]
[li]do nothing (i.e. don’t try to figure it out, let the user correct the voicetrack Ending and/or song cue points!)[/li][/ul]

Both would be equally easy to do: which way would YOU prefer, Charlie?

BFN
CAD

Blimey, our minds think alike!

I reckon the first option would be best… If there is a Ramp on a song, It’s safe to assume that it’s safe to overlay it with something.

Yup, sounds like we both have that programmer’s 'but what if …? mindset! 8)

What I eventually decided though was option 2: if you specify (say) o2 and there isn’t a Ramp2 in the following song, the script will simply give you an error (‘I tried to set this item up, but it failed’). It’s really the user’s problem and should therefore be left to the user to take the action to correct it; all the script should do it is point it out.

I have also implemented a ‘bed’ overlay type (ob), which will start the next item in sync AND set that item’s duration to match the voicetrack’s duration, AND set that item’s fade duration to 500mS (by default, it’s a manifest contstant obviously ;D). Upside: instant talkover beds! Downside: you can’t then ‘talk over’ the song following. So, the track-and-bed is best used ahead of songs which start right away, or have an intro you want to play from 0:00. It’s also brilliant for creating ‘instant ads.’ from a dry voice read and a suitably copyright-free music backing bed which you can then Mix to a file ;).

Not content with that, I also added a ‘start in sync’ type (os), for when you want to force the voicetrack to start in sync with the following song even if that contains Ramps (think about it!). This comes with the minor health warning that it doesn’t check any Ramps in the song, so you need to be sure your voicetrack is short enough if you use this one.

Apart from ‘talkouts’ (starting a voicetrack under the end of a song), which would be near impossible to implement unless you set the song’s StartNext point = its Outro point AND mark the song as say oo (= overlay next from my Outro), I think that between us, we’ve covered all the bases now, yes?

All I would really like to complete the thing—which I’ve renamed IVP for Intelligent Voicetracking Processor—is to find out how to get the number of the current Playlist (usually 1, but you never know, right?). I’ve tried CurrentPlaylist.IndexOf but that doesn’t seem to exist any more. Do you know what I should be using? Or how I get a more up-to-date copy of the script reference Help file?

Once I have that (or give up trying ;)), I’ll be happy to post the finalised version here. It’s pretty neat IMHO. :smiley:

BFN
CAD

CAD/Charlie

I thought that I would jump in here partly as I floated the original idea for this scripts area and also so that you don’t feel alone!

I have been following this thread and the last post proves the old adage that the total is greater than the sum of the individual parts.

I hope to contribute in the future when I have gained more experience in pascal scripts and I am sure some others will do the same!

Keep up the good work guys - look forward to the latest script!

Maybe once ‘final’ versions of the scripts created on the forum are agreed they they can be added to the wiki with functional descriptions…

Ron.

Ron: good to know it’s not just Charlie and I lounging against the back wall in here, chatting over a ciggie! :wink: In case you didn’t look at the latest ZIPfile of the script, there are two copies of the script in there; one is FULLY and I mean FULLY commented to assist learners and tweakers alike; the other contains minimum comments so that it loads and runs that tiny bit faster.

Charlie: With Torben’s help, I have everything figured out now and will post the finalised current version of IVP soon, hopefully later today. I think everyone will like it. 8)

BFN
CAD

Hi Cad, still here following this thread. However not having a programmers background that’s where i’ve been hiding.

Enjoyed everything so far, only wish I had something to contribute.

Kind regards Tony