Dennis Schridde schreef:
>> I think we should just allow the creation of multiple playlists, and then
>> have some function to select the current active one (like bindPlaylist
>> below). Then when you select a playlist to be active it should simply start
>> playing automatically. If you would want nothing to play then just select
>> playlist NULL or something similar, meaning no playlist is active.
>>     
> When everything starts you must have the state playing=no/stoped=yes, because 
> you don't even have a playlist to play from.
> Your idea would imply that bindPlaylist doesn't only bind the playlist, but 
> also implicitly advises the soundengine to play it.
> Doesn't sound too nice to me. 1st that function does several things instead 
> of 
> only one and 2nd the modder might not want to start it immediately for 
> whatever reason.
>   
Nope it would imply that the soundengine would play it if playing=yes.
> Eg. in GL the texture you bind is also not immediately painted on the screen. 
> Or if AL uses a similar way, I don't think every sound-source you bind is 
> immediately played. (But I have _no_ idea of AL, I must admit.)
>   
In fact an ALsource is nothing more than a set of coordinates, a speed
vector (for the Doppler effect), etc.

Anyway, an ALsource _can_ only be played when a filled ALbuffer is
attached to it.
> So my advice would be to let bindPlaylist bind the playlist and let 
> startPlaylist/resumePlaylist handle the beginning playback.
> (Maybe we should have start/stop and pause/resume functions, where start/stop 
> start from the beginning or stop entirely and pause/resume only ... pause and 
> resume. Would save us from weird double namings (start and resume being the 
> same thing) and would also add some functionality for no fees.)
>   
>> That way you would have to provide a single song playlist though. This
>> could be done by a wrapping function though: * creating a playlist
>>  * add the one song to it
>>  * hook some kind of playlistFinished event on it (as a callback function)
>>  * add the ID of the currently playing playlist to a member var of the new
>> playlist * make the new playlist active
>> Then upon raising of playlistFinished event (i.e. through callback
>> function): * make previous playlist active again
>>  * destroy one-track playlist
>>     
> With the bound playlists (GL style architecture) I don't think we need the 
> play-one-track and resume function anymore. I don't even think that we should 
> provide a wrapper for that purpose... More work for us for something the 
> modder can easily achive by himself. Additionaly we need to do some magic 
> with our temporary playlists in the background, which might bring confusion. 
> We would need to find out who created the playlist which just ended to know 
> if we need to inform the scripts or handle it ourselves. (Otherwise we might 
> do some harm to the modders playlist or he might to ours.)
> So IMO lots of work for little benefit.
>   
Yeah probably didn't put that as simple as I could have: don't use a
separate playTrack function, simple let the modder create a one-song
playlist instead.
>>>>>>> Function to stop playlist playback and one function to resume
>>>>>>> playback.
>>>>>>>               
>> Probably would apply to all playlists? I.e. no playlists should be played
>> from at all.
>>
>> That way some `static bool playing;' could accomplish this (i.e. global
>> across all playlists).
>>     
> ?
> start/stop, pause/resume would advise the sound engine to 
> start/stop/pause/resume the current playlist, not one single playlist...
>
>   
Well my idea was this:
You can have only one playlist actively being played from at a time.
Then if that is the case you do not need to control the
playing/paused/stopped state of individual playlists. So you could
effectively use one playing state for the entire playlist handling part
of the soundlib.
> This was _not_ a proposal for the scripting engine, but for the C-API...
> The scripting engine would get some integer IDs or similar...
>   
Yes, well the absence of that WZSound_ prefix was a bit confusing.
>>>>> Hmmm... Actually the idea is not that bad...
>>>>> Would make it easy to handle multiple playlists, eg. one for the menu
>>>>> and for the game, or when The Modder wants to interupt the game with a
>>>>> few different songs to acompany his cutscenes or the attack of the
>>>>> clones... (And wants to switch back to the usual theme afterwards.)
>>>>>
>>>>> Implementation for createPlaylist:
>>>>> New item of a playlist-linked-list. All pointers NULL. (next, prev,
>>>>> thisTrack).
>>>>>
>>>>> addTrack:
>>>>> Walk to the end of Playlist*, check if thisTrack is NULL, yes-> set
>>>>> thisTrack to Track*, no-> append another empty item, link it in, set
>>>>> it's thisTrack.
>>>>>           
>> That implementation would have to require that the same piece of code that
>> manages the playlist also manages the tracks. Because a pointer in that
>> playlist would become invalid as soon as someone removed/destroyed/freed
>> the track without first searching *all* playlists and deleting it from
>> them.
>>     
> I thought the current resource handler would keep track of who wants some 
> resource. If it doesn't I'll fix that together with the rest of it next 
> month.
>   
You mean the MALLOC/FREE wrappers? Those track nothing but debug stuff
(so they're not checking whether a memory chunk is still used or not,
which an allocator can't know btw).
>> In fact I think dynamic arrays (std::vector or std::list) are probably the
>> best way to solve this. Then once your using C++ anyway you might as well
>> use a smartpointer to hold the `track' object which will fix the problem I
>> mentioned above.
>>
>> Such a small usage of C++ should be rather easy to contain/manage in a
>> single (e.g. `lib/sound/playlist.cpp') source file.
>>     
> Well, C doesn't have std::vector, so I had no other idea...
> What I just thought about was some selfmade dynamic array:
> struct Playlist { meta-info; Track[]; }
> malloc( sizeof(meta-info) + sizeof(Track*) * playlistSize );
> or realloc( ... );
> Doesn't look nice, but would be an option...
>   
Yep, I'm quite aware of the fact that C doesn't have an std::vector.
That's why I proposed using some partial C++ code.

And using structs in such a way will require quite a lot of external
managing code (rather than internal, as is with class
constructors/destructors).

Not to mention that when you start producing your own versions of
dynamic arrays, you'd be reinventing the wheel.
>>> And the initial idea why I proposed an implementation was that I thought
>>> that createPlaylist needs to return a pointer to something which we can
>>> see is empty and which first gets filled when we add a track. Probably
>>> the solution would have been obvious to everyone, but I had to think
>>> about it for a second, so I thought it's better if I write it down. Then
>>> I got the idea how simple bindPlaylist could be (I first thought that it
>>> might be very complicated, because the playback needs to be stopped and
>>> buffers need to be cleared and and and...) so I wrote that down, too.
>>>       
>> Simply said, you only need two buffers per playlist.
>>
>> The simplicity of stopping/pausing playback would depend on wether you use
>> one ALsource/playlist or one for all playlists. In the case of one per
>> playlist you could simply set the source to paused on deactivating the
>> current playlist, then upon reactivation set it to play again. (number of
>> ALsources is limited by OpenAL.)
>>     
> One buffer/source per playlist sounds good. If the playlist is stoped (not 
> paused) we could destroy the buffer and the source.
>
> Why are 2 buffers needed? Only case I can imagine is when crossfading, but in 
> that case each playlist has it's buffers it will play from and we only have 
> to adjust the gain between them.
>   
Well unless you would want to decode every song entirely into memory
(e.g. a 5 MB Vorbis-file to 30-40 MB PCM data). I'd prefer using a
streaming method, decoding only chunks at a time and queueing them to be
played by the ALSource, then when those buffers are played free them.
This also spreads out the decoding CPU time (rather than freezing the
game for 20 secs or so).
>> If you were to use one for all playlists however then you have about two
>> (or three) options:
>>
>> one bufferset for all playlists (I believe OpenAL limits the amount of them
>> to 64?): 1) * on pausing: stop the ALsource
>>     * deattach all ALbuffers from it, destroy them
>>     * remember the last playing track (as playlist position)
>>     * then upon resuming simply restart playback from that song
>>
>> one bufferset per playlist.
>>  2) * on pausing: stop the ALsource
>>     * retrieve the order of the currently attached (non-finished) ALbuffers
>>     * deattach all ALbuffers from it (but don't destroy them)
>>     * upon resuming reattach all non-finished ALbuffers to the ALsource in
>> the correct order * start the ALsource again
>>
>> variation on 2, one bufferset for all playlists:
>>  3) * on pausing: stop the ALsource
>>     * retrieve the amount of time of unplayed sound from the buffers
>> (through buffer size/count?) * deattach all ALbuffers from it, destroy them
>>     * upon resuming somehow calculate a new position to start decoding from
>> (should be a bit back if buffers where full) * recreate buffers, decode
>> data to fill them up
>>     * attach them to the ALsource
>>     * start the ALsource again
>>
>> Of these 1 and 3 have the best resource efficiency (e.g. memory, amount of
>> active ALsources/ALbuffers). 1 will probably be even more efficient (in
>> terms of big O), 3 will have better accuracy on time position to resume
>> playing. 2 will probably be the easiest to implement, might have better
>> timing accuracy than 3 and will most certainly have better big O efficiency
>> than 3.
>>
>>     
>>>>>>> Stopping and resuming the playlist may be interesting to create
>>>>>>> moments of total silence or when cutscenes are played.
>>>>>>>
>>>>>>> C-Functions:
>>>>>>> WZSound_setPlaylist( Song * song1, ... );
>>>>>>> WZSound_playTrack( Track interuptionTrack );
>>>>>>> WZSound_stopPlaylist();
>>>>>>> WZSound_resumePlaylist();
>>>>>>> WZSound_setPlaylistMode( PlaylistMode newMode );
>>>>>>>
>>>>>>> typedef PlaylistMode UInt8;
>>>>>>> #define PLAYLIST_SHUFFLE 0x1
>>>>>>> #define PLAYLIST_REPEAT_ALL 0x2
>>>>>>> #define PLAYLIST_CROSSFADE 0x4
>>>>>>> ...
>>>>>>>               
>> What about an enum instead?
>>     
> Doesn't go well with bitwise or...
> ( PLAYLIST_SHUFFLE | PLAYLIST_CROSSFADE ) will not be defined in the enum.
>   
Yes, well the point was I don't like the idea of polluting large pieces
of code by overrunning them with macros. It would also be possible to
use enums with set numbers (e.g. a=1, b=2, c=4, d=8, etc.). That way
only the required parts of the code would have those options available.
>>>>>>> C-Function examples:
>>>>>>> WZSound_setPlaylist( song1, song2, song3 );
>>>>>>> WZSound_setPlaylist( NULL );
>>>>>>> WZSound_setPlaylistMode( PLAYLIST_SHUFFLE | PLAYLIST_CROSSFADE );
>>>>>>>
>>>>>>> Script-Function examples:
>>>>>>> WZSound_setPlaylist( "song1.ogg", "song2.ogg", "song3.ogg" );
>>>>>>>               
>>>>>> Variadic functions won't work, we'll have to fall back to something
>>>>>> like playlistAddSong(song);
>>>>>>             
>>>>> Ok, then I'm fine with Per's playlistAdd and playlistClear functions.
>>>>>           
>>>>>>> WZSound_setPlaylist( "none" );
>>>>>>> WZSound_playTrack( "event1.ogg" );
>>>>>>> WZSound_setPlaylistMode( "shuffle", "fadein" );
>>>>>>> WZSound_setPlaylistMode( "repeat_all", "crossfade", "fadeout" );
>>>>>>> WZSound_setPlaylistMode( "none" );
>>>>>>>               
>> Lets not use Cstrings (or any piece of rope for that matter; i.e. strings)
>> to indicate play modes.
>>     
> This was for the scripting engine. I don't think it supports bitflags, does 
> it? So the first and possibly easiest option was concatenating strings.
> Maybe we could also provide the C-defines (PLAYLIST_SHUFFLE,...) as constants 
> to the scripting engine and add them on another...
>   
Hmm, yes, well your confusing a bit by using WZSound_ in front of those
function names, while you just stated (at least I think so) you'd only
want to use those in the C-codebase. Although I do think it would be
better if we'd use something like defines or constants instead.
> Other idea would be to do it GL style:
> wzBindPlaylist(), wzAddTrack(), ...
> This wouldn't make it obvious out of which engine part the function comes, 
> though. Dunno if that is aceptable.
> LIBNAME_function() is commonly used, I think, so I came up with it 1st.
>   
Yes, I like the LIBNAME_APIfunc style better.

-- 
Giel


Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Warzone-dev mailing list
[email protected]
https://mail.gna.org/listinfo/warzone-dev

Reply via email to