We trigger lyrics in ProPresenter using Ableton (church setting). We use two separate tracks in Ableton… one for calling up the correct song, and another for each of the slide advances in the song. I’m wondering if it’s possible to have Ableset handle calling up the correct song, instead of Ableton. I know I can figure canvas buttons to send MIDI… but can it be automated? I assume this would involve scripting… but I’m wondering if I could have Ableset fire pre-configured commands automatically based on setlist index. So, Song 1 in the setlist (either being cued, or beginning playback) sends the MIDI command for Song 1 to ProPresenter… This would just save me the weekly work of configuring those automations, since as songs change out from week to week, setlist indices in both ProPresenter and AbleSet would still remain in sync…
I know this doesn’t answer your question at all but if you’ve never tried it, I would suggest using Companion by Bitfocus and RossTalk. It’ll change your life. The workflow is SO much easier and better than MIDI (in my opinion of course).
Hey @JoshList,
Would you want the recall song message to fire when the song is selected/cued, or only when you actually hit Play?
Safest for our use case would probably be when we hit play, since there are other slides that get used between songs, that would get skipped if it automatically jumps to the next song when the previous song finishes…
But I could probably make either implementation work, if one was easier to execute than the other…
Hey @JoshList,
Given your note, I’m sharing two script options you can try:
-
Option A: Sends the Program Change every time you press PLAY (Stop → Play).
-
Option B: Sends the Program Change whenever AbleSet switches to a new active song (i.e., when the active song name changes).
Two important requirements (for either option)
-
Song names must match exactly
The keys in yourpcBySongmap must match exactly what AbleSet reports via/setlist/activeSongName(same spelling, capitalization, spaces, punctuation). If there’s no exact match, the script won’t send anything. -
MIDI output device name must match exactly
const midiOutput = "ProPresenter MIDI"must be identical to the MIDI output name you see/select in AbleSet.
Option A — Send PC on PLAY (Stop → Play)
// MIDI output that goes to ProPresenter
const midiOutput = "ProPresenter MIDI"; // must match the output name in AbleSet
// Song name → Program Change mapping
// Keys MUST match exactly what AbleSet reports via /setlist/activeSongName
const pcBySong = {
"Song 1": { program: 1, channel: 1 },
"Song 2": { program: 2, channel: 1 },
"Song 3": { program: 10, channel: 2 },
// "Oceans": { program: 23, channel: 1 },
};
log("Project Script started (Send PC on PLAY)");
// Edge-detect Stop -> Play
let wasPlaying = false;
let lastSentAt = 0;
const DEDUPE_MS = 200;
onOscChange(
"/global/isPlaying",
([playing]) => {
const isPlaying = !!playing;
// Stop -> Play
if (isPlaying && !wasPlaying) {
const now = Date.now();
if (now - lastSentAt < DEDUPE_MS) {
wasPlaying = isPlaying;
return;
}
const songName = osc("/setlist/activeSongName");
log("PLAY pressed. Active song is:", songName);
const data = pcBySong[songName];
if (!data) {
log("No Program Change mapped for song:", songName);
wasPlaying = isPlaying;
return;
}
const channel = data.channel ?? 1;
const program = data.program;
sendOsc("/midi/send/pc", midiOutput, channel, program);
lastSentAt = now;
log(`Sent PC ${program} on channel ${channel} to "${midiOutput}" for song "${songName}"`);
}
wasPlaying = isPlaying;
},
true
);
Option B — Send PC when the active song changes
// MIDI output that goes to ProPresenter
const midiOutput = "ProPresenter MIDI"; // must match the output name in AbleSet
// Song name → Program Change mapping
// Keys MUST match exactly what AbleSet reports via /setlist/activeSongName
const pcBySong = {
"Song 1": { program: 1, channel: 1 }, // Program Change #1 on channel 1
"Song 2": { program: 2, channel: 1 },
"Song 3": { program: 10, channel: 2 },
// "Oceans": { program: 23, channel: 1 },
};
log("Project Script started (PC mode)");
onOscChange(
"/setlist/activeSongName",
([newSong]) => {
log("Song changed to:", newSong);
const data = pcBySong[newSong];
if (!data) {
log("No Program Change mapped for song:", newSong);
return;
}
const channel = data.channel ?? 1;
const program = data.program;
// Send Program Change
sendOsc("/midi/send/pc", midiOutput, channel, program);
log(
`Sent PC ${program} on channel ${channel} to "${midiOutput}" for song "${newSong}"`
);
},
true // fire immediately with current value
);
Let me know which behavior fits better for your workflow.
Also: what exact MIDI message does ProPresenter expect on your end (PC vs CC vs Note)?
If it’s not a Program Change you’re sending, these scripts can be adjusted in the same style.
I’m looking forward to your reply!
Wow, thank you so much for putting these together! you guys seriously go above and beyond. I’m definitely out of my depth when it comes to scripting, but if I’m reading it right, it seems like this will require updating song names in the script itself?
We have a big project file with probably around 90 songs in it, and we only do 4-5 songs on any given Sunday, so the songs in the setlist are getting swapped out every week. So my hope was to create automations that would just be based on the song index number in the current setlist, rather than song name, since that would have to get updated every week. I know that index number is a usable OSC value, because I use it on some of my canvas buttons…
So, instead of sending PC1 when “song name” starts playing… it would send PC1 when “Song 1” starts playing. That way, on any given week, no matter what song is first in the setlist, it’s always going to send PC1 for the first song, PC2 for the second, and so on and so forth…
Hopefully I’m making sense…
Hey @JoshList,
In ProPresenter, does Song 1 always point to the same presentation, or do you have a unique presentation per song?
The midi automations just call up an item number in a ProPresenter playlist. The presentation/item at that spot in the playlist changes out every week in the same way that the songs in the ableset setlist do.
So the way we have it set right now…
“Note On, G-1” is the command for calling up an item in the playlist (the playlist includes the five songs for the morning, plus teaching slides, some announcements, etc), and the velocity of the note is the index for the item in the playlist that we’re calling up. So if the first song is the second item in the playlist, I have Ableton send “G-1, velocity 2” at the start of the song. The number of items in our services and the order in which we do them, don’t change much. But the songs themselves do change out. So I’m just hoping for a bit of a “set it and forget it” connection between song index in the ableset setlist, and playlist placeholder numbers in the ProPresenter playlist.