SteveH Posted May 26, 2008 Share Posted May 26, 2008 (edited) Background: Cakewalk Sonar Home Studio is a 'Digital Audio Workstation' or music sequencer program. In the 'Producer' version there is a 'Fit Improvisation' command not available in the 'Home Studio' version. 'Fit Improvisation' calculates a new midi tempo every beat in order to synchronize a midi track with an audio track. For example, you start by recording an acoustic piano piece onto an audio track. On a midi track, you play a note for each beat of the audio track. Then you apply the 'Fit Improvisation'. Now the midi beat is synchronized with the audio. You can add midi drums/base tracks that match the audio.Problem: I'm not interested in paying $$$ for a professional class upgrade of software that I use as a hobby at home. So I decided to find another way to apply 'Fit Improvisation'Solution: I found AutoIT... AMAZING!. My script uses mainly keystroke emulation to parse throught the midi track and gather the exact time for each note. Within the script, the new tempo is calculated based on the difference in time between 2 notes. Keystroke emulation enters the new tempo at the appropriate time.This script is not elaborate, but it works. I'm not sure that anyone else would have any interest in this but I thought I would post it anyways.The (.exe and) source files are attached, but here is the main script:expandcollapse popupAutoItSetOption("WinTitleMatchMode",2) If WinExists("Help") then WinClose("Help") ;program mixes up Sonar Help window with Sonar progam If WinExists("Synth Rack") then WinClose("Synth Rack") ;synth rack is always on top and gets in the way WinActivate("SONAR") If WinActive("SONAR")=0 Then MsgBox(16, "ERROR", "Unable to find SONAR") Exit EndIf $message=FileRead("Fit Improv ReadMe.txt") If MsgBox(65, "Fit Improvisation Instructions:", $message)<>1 Then Exit AutoItSetOption("SendKeyDelay", 50) ;increase value to slow down typing speed Send("^{Home}") ;rewind to beginning Send("!esn") ;unselect clips ;set variables... Send("!op") $timebase = InputBox("TIMEBASE", "What is the TIMEBASE (Ticks per quarter note) ?", "960","",-1,-1,0,0) If WinExists("Project Options") then WinClose("Project Options") $events = InputBox("Number of Events to Process", "How many Events/Notes in Selected track ? (Don't know?... double click the track to open/view the track properties)", "0","",-1,-1,0,0) If WinExists("Track Properties") then WinClose("Track Properties") WinActivate("SONAR") If $events = 0 Then Exit Send("!ik{TAB}^c{Enter}") $bpmeasure = ClipGet() Send("!it^c{Enter}") $basetempo = ClipGet() ProgressOn("Progress Meter", "Do NOT touch your keyboard or mouse", "Progress Meter: 0 percent",0,0,1) for $time = 0 to (($events-1)*$timebase) Step $timebase ;move to next note Send("{F3}") ;get current transport time Send("!gt^c{Enter}") $transport=ClipGet() ;convert transport from M:B:T to ticks $MBT = StringSplit( $transport , ":" ) $tick = ($MBT[1]-1)*$bpmeasure*$timebase + ($MBT[2]-1)*$timebase + $MBT[3] if $time > 0 then $move=$tick-$mark ;number of ticks from last event $tempo=Round(($basetempo*$timebase/$move) , 2) ;MsgBox(4096, "Tempo", $tempo , 10) $measure=INT(($time-$timebase)/($timebase*$bpmeasure))+1 $beat=INT((($time-$timebase)-(($measure-1)*$timebase*$bpmeasure))/$timebase)+1 If $tempo < 8 then If MsgBox(17, "Tempo Error:", "The calculated tempo of " & $tempo & " (Measure " & $measure & ", Beat " & $beat & ") is too low")<>1 Then Exit ElseIf $tempo > 1000 Then If MsgBox(17, "Tempo Error:", "The calculated tempo of " & $tempo & " (Measure " & $measure & ", Beat " & $beat & ") is too high")<>1 Then Exit Else ;enter new tempo at measure:beat Send("!it") Send($tempo) Send("!it") Send($measure) Send(".") Send($beat) Send("{Enter}") EndIf EndIf $mark=$tick $i=Round($time/(($events-1)*$timebase)*100,0) ProgressSet( $i, "Progress Meter: " & $i & " percent") next Send("^{Home}") ;rewind to beginningFit_Improv.au3 Edited May 27, 2008 by SteveH Link to comment Share on other sites More sharing options...
CoderDunn Posted May 26, 2008 Share Posted May 26, 2008 (edited) Cool keep up the good work. Interesting way to use the clip board. Look into the BlockInput() function to prevent someone from using the keyboard or mouse while it's working. Just make sure you enable the user input when it's finished! Edited May 26, 2008 by Hallman Link to comment Share on other sites More sharing options...
SteveH Posted May 26, 2008 Author Share Posted May 26, 2008 Thanks for the suggestion Hallman... There would definitly be a problem with the accuracy of the script if the keyboard is touched during the process. A 3 minute song at 75 beats per minute results in 225 events to be processed... it takes a few minutes (thus the progress bar). I figured out how to use AutoIT from the Help file and online examples. Didn't know about the BlockInput() function. Looks like it wouldn't work properly on Windows 98 or Windows XP if SP2 not installed. I see in the Help file that I can use @OSVersion to detect Win98 but how can I detect WinXP with only SP1? (Not a big deal for me... using WinXP SP3 or Vista) I think I will update the script with BlockInput() anyways. Thanks. Link to comment Share on other sites More sharing options...
SteveH Posted May 27, 2008 Author Share Posted May 27, 2008 Here is the updated script using the BlockInput() function to prevent the user from typing on the keyboard while the script is running. I updated the Zip attachments on the 1st post. expandcollapse popupAutoItSetOption("WinTitleMatchMode",2) If WinExists("Help") then WinClose("Help") ;program mixes up Sonar Help window with Sonar progam If WinExists("Synth Rack") then WinClose("Synth Rack") ;synth rack is always on top and gets in the way WinActivate("SONAR") If WinActive("SONAR")=0 Then MsgBox(16, "ERROR", "Unable to find SONAR") Exit EndIf $message=FileRead("Fit Improv ReadMe.txt") If MsgBox(65, "Fit Improvisation Instructions:", $message)<>1 Then Exit AutoItSetOption("SendKeyDelay", 50) ;increase value to slow down typing speed Send("^{Home}") ;rewind to beginning Send("!esn") ;unselect clips ;set variables... Send("!op") ;open project options dialogue so user can verify 'Ticks per quarter note' = 960 $timebase = InputBox("TIMEBASE", "What is the TIMEBASE (Ticks per quarter note) ?", "960","",-1,-1,0,0) If WinExists("Project Options") then WinClose("Project Options") $events = InputBox("Number of Events to Process", "How many Events/Notes in Selected track ? (Don't know?... double click the track to open/view the track properties)", "0","",-1,-1,0,0) If WinExists("Track Properties") then WinClose("Track Properties") WinActivate("SONAR") If $events = 0 Then Exit If @OSVersion <> "WIN_98" And @OSVersion <> "WIN_ME" Then BlockInput(1) ;block user input while script running EndIf Send("!ik{TAB}^c{Enter}") ;open Meter/Key Signature dialogue and select/copy 'beats per measure' $bpmeasure = ClipGet() Send("!it^c{Enter}") ;open Tempo dialogue and select/copy baseline tempo $basetempo = ClipGet() ProgressOn("Progress Meter", "Fit to Improvisation", "Progress Meter: 0 percent",0,0,1) for $time = 0 to (($events-1)*$timebase) Step $timebase Send("{F3}") ;move to next note Send("!gt^c{Enter}") ;open 'Go' dialogue and select/copy current transport time $transport=ClipGet() ;convert transport from M:B:T to ticks $MBT = StringSplit( $transport , ":" ) $tick = ($MBT[1]-1)*$bpmeasure*$timebase + ($MBT[2]-1)*$timebase + $MBT[3] if $time > 0 then $move=$tick-$mark ;number of ticks from last event $tempo=Round(($basetempo*$timebase/$move) , 2) ;MsgBox(4096, "Tempo", $tempo , 10) $measure=INT(($time-$timebase)/($timebase*$bpmeasure))+1 $beat=INT((($time-$timebase)-(($measure-1)*$timebase*$bpmeasure))/$timebase)+1 If ($tempo < 8 or $tempo > 1000) then BlockInput(0) If MsgBox(17, "Tempo Error:", "The calculated tempo of " & $tempo & " (Measure " & $measure & ", Beat " & $beat & ") is out of range")<>1 Then Exit If @OSVersion <> "WIN_98" And @OSVersion <> "WIN_ME" Then BlockInput(1) ;block user input while script running EndIf Else ;enter new tempo at measure:beat Send("!it") Send($tempo) Send("!it") Send($measure) Send(".") Send($beat) Send("{Enter}") EndIf EndIf $mark=$tick $i=Round($time/(($events-1)*$timebase)*100,0) ProgressSet( $i, "Progress Meter: " & $i & " percent") next Send("^{Home}") ;rewind to beginning BlockInput(0) ;turn off block input Link to comment Share on other sites More sharing options...
CoderDunn Posted May 27, 2008 Share Posted May 27, 2008 (edited) Here is the updated script using the BlockInput() function to prevent the user from typing on the keyboard while the script is running. I updated the Zip attachments on the 1st post.Cool It's nice to see a newcomer that actually puts in the effort to figure out things himself instead of expecting us to tell him everything Keep it up! I'm interested in seeing what you post in the future.~ HallmanNote: Typically posting just the source is sufficient for smaller scripts like this. It is, of course entirely your decision, but people are much less likely to download a zip or exe than a plain au3 (Not to mention it uses less of the forums bandwidth). Edited May 27, 2008 by Hallman Link to comment Share on other sites More sharing options...
SteveH Posted May 27, 2008 Author Share Posted May 27, 2008 Just the .au3 script is attached to the first post now. Thanks for the tip Hallman. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now