I was really excited about the announcement for a midi player in GP4. However I’m struggling to sync an audio player with the midi player. My use case is as follows. I am running a backing track on one instance of GP4 which I control track selection and start/stop playback with a Behringer FCB1010 over midi.
In the backing track instance I want to add a midi player which starts at the same time as the audio player and will trigger LightKey (midi) and my lighting rig.
I’ve added a button to the rackspace to control play start on both, however I can’t find a way of syncing them up.
The left green button starts the Audio File Player and the MIDI File Player
The middle red button stops both
With the right blue button you can start the MIDI File Player separately.
And here is the script used:
Var
AFP : PluginBlock
MFP : PluginBlock
STAAP : Widget
STOAP : Widget
STAMP : Widget
// Called when a single widget value has changed
On WidgetValueChanged(newValue : double) from STAAP
if newValue == 1.0 then
STAMP.SetWidgetValue(newValue)
end
End
On WidgetValueChanged(newValue : double) from STOAP
if newValue == 0.0 then
STAMP.SetWidgetValue(newValue)
end
End
And here a gig where the 2nd rackspace does not even need scripting.
With the left button you can start/stop Audio File Player and MIDI File Player
And with the global playhead in the top of the window you can do the same. Start_AP_MP.gig (91.0 KB)
Thank you so much for both examples! It definitely does what I need it to but I’m struggling to reverse engineer the second example to create in my own rackspaces. Would you be able to tell me the steps?
Great thread. I’d love to request that this become a standard feature; or even that GP add a “midi/audio time lock” button which keeps specific midi files synced with specific audio “multis.”
Or, flesh out the midi player to include an additional eight tracks of audio which play back along with the midi play head.
My perfect world would have midi “song forms” for each tune, as well as a midi click synced to the form, audio backing tracks to be sent to the PA, stems for each band member’s parts in audio OR midi (for rehearsals when they can’t make it)… sent to separate channels, and the ability to embed midi command events on a dedicated timeline right within the editor. (To trigger effects and tone changes within gig performer or external hardware. In time with the sequence.)
For now I’m extremely pleased with the GP4 features and your write up. @pianopaul!
It certainly would be really cool if you could sync up midi playback and audio playback against a song in song/set mode. My typical usecase here is for each song I have various rackspaces for (intro, verse, chorus etc). For all songs I want to start an audio backing track at the same time as a midi file which controls my lighting rig using a USB DMX interface. I connect the MIDI player to the midi Input of LightKey (mac).
I’m getting all of that working in GP4 as it works now and it’s brilliant as it’s the first time I’ve been able to do this easily. But having improve synchronisation and linking a “global rackspace” for the song which I could have a timeline to change rackspaces when I reach sections of the song (verse, chorus) would be immense and allow me to focus on the performance and let GP4 deal with making sure I’m on the right patch.
We’re definitely in similar boats. I too am planning to automate lights through midi events, as well as +4dB lead vocal and solo bumps on my digital mixer, video screen events, and more. You’re right of course: GP handles this through song parts, so the natural evolution would prioritize the selection of song parts from a unified, midi-track-synced “conductor track” at the song level.
With scripting in the on BeatChanged callback you can easily implement sending messages whatever you want.
Automatically switch variations, crossfades etc.
I’m in a constant state of anxiety over things like this. I love (love) to jump down rabbit holes and code things to my will at a granular level… but I hate (hate) troubleshooting these solutions 18 months later when I need to alter them right before a gig. I’ve learned the value of canonized, documented, beta-tested, community-forum-backed changes to the base software.
So… I will ponder the implications. Very good to know, however, that these things are possible. I have been trying to stave off using Ableton Live as my in-show ‘source of truth,’ due to expense and redundant features, and your answers pull me inextricably closer to leaving GP on that throne.
(I assume the callback you’re referring to is accessed via GP Script? Haven’t touched GP Script yet, but I’m feeling that urge!)
And here an example what I do within GP and how I control Ableton Live via OSC.
When I select a rackspace in GP then the corresponding Ableton Live scene is selected.
When I press the global play in GP the previous select scene is triggered and when I press the Global Play again, the scene is stopped.
The Global Play I mapped to the play button in my S88.
For the communication between GP and Ableton Live I created a simple M4L patch and loaded it in Ableton Live.
So I have the best of both worlds
var
v_counter : int;
v_beat : int;
v_bar : int;
beat : Widget
MASTER : Widget
KLICK : Widget
SAMPLES : Widget
DRUMS : Widget
BASS : Widget
MBASS : Widget
MDRUMS : Widget
EMBASS : ExternalWidget
EMDRUMS : ExternalWidget
mOSC : OSCMessage
mOSCP : OSCMessage
mOSCT : OSCMessage
function SetPart(index : integer)
if InSetlistMode() then
SetSongPart(index)
else
SetVariation(index)
end
end
On BeatChanged(Bar : Integer, Beat : Integer, Subbeat : Integer)
var v_pointer : String;
v_counter = v_counter+1;
//Print(v_counter);
v_pointer = ""+Bar+"."+Beat
SetWidgetLabel(beat, v_pointer)
If v_counter == 1 then
SetPart(0)
end
If v_pointer == "4.2" then
SetPart(1);
end
if v_pointer == "39.4" then
SetPart(2);
end
if v_pointer == "47.1" then
SetPart(3);
end
if v_pointer == "54.2" then
SetPart(4);
end
if v_pointer == "56.1" then
SetPart(5);
end
if v_pointer == "95.2" then
SetPart(6);
end
if v_pointer == "102.4" then
SetPart(7);
end
if v_pointer == "109.4" then
SetPart(8);
end
if v_pointer == "111.1" then
EnablePlayhead(false)
end
End
on Activate
if BindExternalWidget(EMBASS, "MBASS", "GLOBAL RACKSPACE") then
SetWidgetValue(MBASS,GetExternalWidgetValue(EMBASS))
end
if BindExternalWidget(EMDRUMS, "MDRUMS", "GLOBAL RACKSPACE") then
SetWidgetValue(MDRUMS,GetExternalWidgetValue(EMDRUMS))
end
v_beat = 0
v_bar = 1
SetWidgetLabel(beat, "1.1")
SetPart(0)
OSC_SetAddress(mOSCP, "/SelectScene")
OSC_AppendIntArg(mOSCP, 47)
OSC_SendSpecific(mOSCP, "127.0.0.1", 8000)
OSC_ClearArgs(mOSCP)
OSC_SetAddress(mOSCP, "/SetSongName")
OSC_AppendStringArg(mOSCP, GetRackspaceName())
OSC_SendSpecific(mOSCP, "127.0.0.1", 8000)
OSC_ClearArgs(mOSCP)
SetWidgetValue(MASTER, GetWidgetValue(MASTER))
end
// Called on attempt to change playhead status
On SystemEvent(newValue : double) Matching PlayheadStateChanged
if newValue == 1.0 then
v_beat = 0
v_bar = 1
EnablePlayhead(true)
//Start = MakeControlChangeMessage(112,127)
//SendNowExternal(ABLETON, Start)
OSC_SetAddress(mOSC, "/LaunchScene")
OSC_SendSpecific(mOSC, "127.0.0.1", 8000)
else
EnablePlayhead(false)
end
End
I have 4 Songs (audio files) that play in a Rackspace. I need each song to pay a specific Midi Track loaded in the Midi Player. It occurs to me that using a different Midi player for each song would solve it?
No - they would all still be triggered from the Global play