Hello,
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:
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.
The "Players_Align" moves currentTIme of each player and defines callbacks in in audio_0_player when they should start.
The "Player_Start_Players" start audio_0_player. audio_0_player will send messages to start the other players according to tCallbackList in the audio_0_player.
I have also put the code below in the audio_{1:5}_player's, which I think improves the sync a bit:
Despite this, I can sometimes hear that the players are not playing in sync.
Now my questions!
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
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:
-- Start player(s)-----------------------------------------------------------------------------------------command Player_Start Players_Align wait 10 ticks with messages -- Flush messages Player_Start_Playersend Player_Start
CODE:
-- 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 ifend Players_Align
CODE:
-- 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:
on playerStartedset 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
Statistics: Posted by pklum — Sat Jan 18, 2025 3:43 pm