Author Topic: onMusicLoop event?  (Read 1005 times)

Please, could someone make an onMusicLoop event? For example...

onActivate > Client > setMusic > musicA
onMusicLoop > Client > setMusic  > musicB

So now if musicA reaches its end and loops, instead of looping it'll switch to musicB.

Please, again?
« Last Edit: November 13, 2017, 09:58:58 PM by Sideswipe »

This may not be possible without reading the metadata of the ogg files

I don't think music is actually synced to the server. The music would be looping at different times for each player

I don't think music is actually synced to the server. The music would be looping at different times for each player
That's okay, I'm going to play them clientside anyways. Like this

onActivate > Client > setMusic > musicA
onMusicLoop > Client > setMusic  > musicB

I don't remember the addon that adds Client > setMusic but that's what I have and that's what I'll use.

Still not recommended because it will still be out of sync. If you want it to call it right after you'll need to have a client-side add-on with this..

it won't be very far out of sync since it will be client sided, you can record the client's ping and add that to the end of the song duration to get about the time when it will end

the only thing you'd need is some janky code to figure out the duration of the songs
alxGetWaveLen(filepath)

but only seems useable from the client side
« Last Edit: November 14, 2017, 04:21:24 AM by Swollow »

I wrote some hacky little code that requires you to generate a music table from the client side so if youre running a dedicated server this will only work if you generate a music table before hand on a client side, it stores the length of each song by their crc and then allows retrieaval

client.cs
Code: [Select]
function repeatStr(%str,%num)
{
%ret = "";
for(%i=0;%i<%num;%i++)
%ret = %ret @ %str;
return %ret;
}
function createMusicLenTable()
{
$Swol_SongLenTableConfig = "config/server/songLengths.cs";
if(isFile($Swol_SongLenTableConfig))
exec($Swol_SongLenTableConfig);
%pattern = "Add-Ons/Music/*.ogg";
%file = findFirstFile(%pattern);
$Swol_SongLenTableCnt = 0;
$Swol_SongLenTableUCnt = 0;
echo("\c5Creating MusicLen table");
while(%file !$= "")
{
$Swol_SongLenTable[$Swol_SongLenTableCnt] = %file;
$Swol_SongLenTableCnt++;
%file = findNextFile(%pattern);
}
createMusicLenTableTick(0);
}
function createMusicLenTableTick(%tick)
{
cancel($Swol_SongLenTableSched);
%file = $Swol_SongLenTable[%tick];
%crc = getFileCRC(%file);
if(getSubStr(%crc,0,1) $= "-")
%crc = "M" @ getSubStr(%crc,1,99);
if($Swol_SLen[%crc] $= "")
{
%len = alxGetWaveLen(%file);
%base = fileBase(%file);
if(%len == 0)
{
echo("\c2 > BAD OGG MAY BE IN ZIP OR JUST CORRUPTED (" @ %base @ ")");
}
else
{
$Swol_SLen[%crc] = %len;
echo("\c1 > " @ %base @ repeatStr(" ",50-strLen(%base)) @ (mFloor(%len/1000)) @ "s");
}
%noSkip = 1;
$Swol_SongLenTableUCnt++;
}
if(%tick >= $Swol_SongLenTableCnt-1)
{
createMusicLenTableEnd();
return;
}
$Swol_SongLenTableSched = schedule((%noSkip ? 32 : 1),0,createMusicLenTableTick,%tick++);
}
function createMusicLenTableEnd()
{
cancel($Swol_SongLenTableSched);
echo("\c5MusicLen generation table complete");
echo("  \c5Added " @ $Swol_SongLenTableUCnt @ " song" @ ($Swol_SongLenTableUCnt != 1 ? "s" : ""));
export("$Swol_SLen*",$Swol_SongLenTableConfig);
deleteVariables("$Swol_SongLenTable*");
}

schedule(1,0,createMusicLenTable);

server.cs
Code: [Select]
function execMusicLenTable()
{
$Swol_SongLenTableConfig = "config/server/songLengths.cs";
if(isFile($Swol_SongLenTableConfig))
{
exec($Swol_SongLenTableConfig);
echo("MusicLen table found and executed");
}
else
{
echo("MusicLen table not generated");
}
}
function getMusicLength(%file)
{
%crc = getFileCRC(%file);
if(getSubStr(%crc,0,1) $= "-")
%crc = "M" @ getSubStr(%crc,1,99);
%ms = $Swol_SLen[%crc];
return %ms;
}
schedule(1,0,execMusicLenTable);


this code will run when you boot up blockland and it may hog some resources while it generates the first table, afterwards it shouldn't take as long


then on the server end it will execute the table and then you can find the length of an ogg file by using the server command, for example:

Code: [Select]
echo(getMusicLength("Add-Ons/Music/Piano_Bass.ogg"));
which will echo "6000" (fun fact piano bass is down to the millisecond exactly 6 seconds)




this is my solution if anyone wants to build on it use it etc feel free
implementing this to music loop would work something like

>store client's current ping
>get length of song you want to play
>play song on client
>start a schedule for client's ping+length of song
>at end of schedule play next song or stop song

there will obviously be some clipping issues because of fluctuating ping but you will be pretty close to when the song stops playing on the client side although you will want to do some calculations in realtime incase the server lags and offsets this schedule since the song will continue to play even if the server lags so the schedule should probably be a repeating schedule that does realtime checks

heres an example of some pseudoy code for the job

Code: [Select]
function gameConnection::onSongEnd(%cl,%emitter)
{
%cl.songsPlayingSet.remove(%emitter);
%emitter.delete(); //stop emitter?
if(%cl.songsPlayingSet.getCount() == 0)
{
realTimeSongEndTickSet.remove(%cl);
}
//do stuff
}
function gameConnection::playSongOnClient(%cl,%db)
{
%ping = %cl.getPing();
%size = getMusicLength(%db.filename);

%emitter = create audio emitter really far away
%emitter.scopeToClient(%cl);

%cl.realSongEnd[%emitter] = getRealTime()+%ping+%size;
if(!isObject(%cl.songsPlayingSet))
{
%cl.songsPlayingSet = new simSet();
}
%cl.songsPlayingSet.add(%emitter);
%set = realTimeSongEndTickSet;
%set.add(%cl);
realTimeSongEndTick();
}
function realTimeSongEndTick()
{
cancel($swol_realTimeSongEndTickSched);
%set = realTimeSongEndTickSet;
if((%c = %set.getCount()) == 0)
return;
%time = getRealTime();
for(%i=0;%i<%c;%c++)
{
%cl = %set.getObject(%i);
%sset = %cl.songsPlayingSet;
%songs = %sset.getCount();
for(%a=0;%a<%songs;%a++)
{
%song = %sset.getObject(%a);
if(getRealTime()-%cl.realSongEnd[%song] >= 0)
{
%cl.onSongEnd(%song);
}
}
}
$swol_realTimeSongEndTickSched = schedule(1000,0,realTimeSongEndTick);
}
package swol_songEnd
{
function gameConnection::onDrop(%cl)
{
if(isObject(%cl.songsPlayingSet))
%cl.songsPlayingSet.delete();
return parent::onDrop(%cl);
}
};
activatePackage(swol_songEnd);
if(!isObject(realTimeSongEndTickSet))
new simSet(realTimeSongEndTickSet);

pardon all my bad variable and function names i know theyre awful
« Last Edit: November 14, 2017, 05:27:02 AM by Swollow »

I don't think music is actually synced to the server. The music would be looping at different times for each player
That seems like a hazard, but when you think about it, the music should only be interrupted once. If you were to make a playlist of songs, then once a new song starts playing, everybody should start listening to the song at the same time. I’ve wanted a system like this for a really long time. Technically you could do it with onrelay events, but it would be tedious, and adding in a new song or two would take a lot of bricks used as timers and quite a bit of calculation.