Audio Player / Midi Player Sync

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.

Any ideas?

For my understanding:
Do the Audio File Player and MIDI File Player start at the same time when you start it?

No - if I start the global playback then the audio file starts but the midi player doesn’t. The only way I can get it to start is either:

a) press play on the midi player UI
b) create a button and map it to Play for the Midi Player.

But neither options allow me to sync both from global playback or from a single button.

What i’d like to happen is when I start playback for that song in the set then it starts both the midi and the audio together.

Ok, let me check.

Here you go
Start_AP_MP.gig (52.4 KB)

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
2 Likes

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)

1 Like

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?

Actually, I have figured it out from your example now. I needed to map the Audio Player button System Actions and Play.

Thank you! I really appreciate you taking the time to put the examples together.

2 Likes

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!

2 Likes

Some great ideas @celoranta

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.

2 Likes

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.

1 Like

With scripting in the on BeatChanged callback you can easily implement sending messages whatever you want.
Automatically switch variations, crossfades etc.

2 Likes

Good to know!

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!)

Yes in GP Script

1 Like

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 :wink:

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
1 Like

Ok yeah, I needs to get into that. Riiiiight down my alley.
Thanks as always!