this is my first post ever on a forum, so bear with me ...
A little about me!
I consider myself quite knowledgeable in HyperTalk (started back in 1993). During 2000-2010 programming in HyperTalk was down (cheated a bit in Flash/ActionScript during that time) before I discovered Livecode in 2011. Since then have been faithful to Livecode.
I am currently developing a desktop application (macOS/Win) for musicians where you can play music (mp3) synchronized with lyrics and chords, called BandAid. I plan to release the application on the Mac App Store and Microsoft Store this summer 2025.
In BandAid I use Spleeter (search on GitHub) using "open process" and CLI calls to Spleeter to create separate stems from an mp3 file. I then want to be able to play the stems in sync and mix these together in BandAid.
The problem is that I have a hard time getting the stems to play in sync with each other.
As an example, I have six audio files (*.mp3) loaded into six hidden players:
- audio_0_player loaded with the file "original" - contains the original mp3 not Spleeted. (reference audio track)
- audio_1_player loaded with the file "drums" - contains the drum stem.
- audio_2_player loaded with the file "other" - contains guitar/keyboard stem
- audio_3_player loaded with the file "piano" - contains the piano stem.
- audio_4_player loaded with the file "bass" - contains the bass stem.
- audio_5_player loaded with the file "vocals" - contains vocal stem.
If I start the player one after the other, the previously started player widget will continue playing until the time it takes to execute the start command for the next player widget - why they are not synchronized in time. This is something that I find difficult to control.
I have tried a variety of ways to get these players to play synchronized with "send in time", "wait 0 with messages", "lock messages, ...
The latest and most successful version is to use audio_0_player (muted to avoid slapback echo) as a reference and create callbacks in audio_0_player to start the other players after each other. To separate the start of the different player, I move currentTime for each player before start timeScale/10 intervals after each player.
global gState["PlayerList"] contains a list of all player with loaded files with their short names.
global gState["MainTimescalePlayer"] contains the timeScale of the files.
global gState["PlayRate"] contains the current set playrate.
The command Players_Stop stops all player widgets
The command "Player_Start" starts the sequence.
Code: Select all
-- Start player(s)
-----------------------------------------------------------------------------------------
command Player_Start
Players_Align
wait 10 ticks with messages -- Flush messages
Player_Start_Players
end Player_Start
Code: Select all
-- Move currentTime of each player {1:5} and create player {1:5} start callbacks in audio_0_player
-----------------------------------------------------------------------------------------
command Players_Align
Players_Stop -- Stops all players
set the callbacks of player "audio_0_player" of me to empty
if the number of lines in gState["PlayerList"] > 1 then
-- Multi-track
put the currentTime of player "audio_0_player" of me into tRef
put gState["MainTimescalePlayer"]/10 into tIntervalDelay
put empty into tCallbackList
repeat with tPlayerNum = 2 to number of lines in gState["PlayerList"]
-- First line is audio_0_player
if line tPlayerNum of gState["PlayerList"] is empty then next repeat
put (tRef + tIntervalDelay*(tPlayerNum-1)) into tStartInterval
put line tPlayerNum of gState["PlayerList"] into tPlayer
set the currentTime of player tPlayer of me to tStartInterval
put tStartInterval, "Player_Start_Player" & (tPlayerNum-1) into line (tPlayerNum-1) of tCallbackList
end repeat
set the callbacks of player "audio_0_player" to tCallbackList
end if
end Players_Align
Code: Select all
-- Start Reference player audio_0_player
-----------------------------------------------------------------------------------------
command Player_Start_Players
set the playrate of player "audio_0_player" of me to gState["PlayRate"]
end Player_Start_Players
-- Start audio_1_player from audio_0_player callback
-----------------------------------------------------------------------------------------
command Player_Start_Player1
set the playrate of player "audio_1_player" of me to gState["PlayRate"]
end Player_Start_Player1
-- Start audio_2_player from audio_0_player callback
-----------------------------------------------------------------------------------------
command Player_Start_Player2
set the playrate of player "audio_2_player" of me to gState["PlayRate"]
end Player_Start_Player2
-- Start audio_3_player from audio_0_player callback
-----------------------------------------------------------------------------------------
command Player_Start_Player3
set the playrate of player "audio_3_player" of me to gState["PlayRate"]
end Player_Start_Player3
-- Start audio_4_player from audio_0_player callback
-----------------------------------------------------------------------------------------
command Player_Start_Player4
set the playrate of player "audio_4_player" of me to gState["PlayRate"]
end Player_Start_Player4
-- Start audio_5_player from audio_0_player callback
-----------------------------------------------------------------------------------------
command Player_Start_Player5
set the playrate of player "audio_5_player" of me to gState["PlayRate"]
end Player_Start_Player5
Code: Select all
on playerStarted
set the currentTime of me to the currentTime of player "audio_0_player"
end playerStarted
Now my questions!
- Does anyone have an idea how to sync player widgets?
- I have not find a method to measure the synchronization between the players (must use my ears!). Any idea how to measure this?
- Is mp3 an inappropriate format for synchronizing playback?
A completely different question!
I use . (period) as a delimiter in my handler names, but had to change it to _ (underscore) as the Forum editor thought I was creating external links. Is there any way around it? Strangely enough, it was possible to write (*.mp3) above!?!?
Regards,
pklum
I develop (today) on macOS Sequoia 15_2, Mac Mini M1, Livecode 10_0_1 (rc 3). I also check that the code works under Windows 10