Am Donnerstag, 25. Januar 2007 15:46 schrieb Giel van Schijndel:
> On Thu, 25 Jan 2007 07:31:25 +0100, Dennis Schridde <[EMAIL PROTECTED]> 
wrote:
> > Am Donnerstag, 25. Januar 2007 01:21 schrieb Troman:
> >> ----- Original Message -----
> >> From: "Dennis Schridde" <[EMAIL PROTECTED]>
> >> To: <[email protected]>
> >> Sent: Thursday, January 25, 2007 12:26 AM
> >> Subject: Re: [Warzone-dev] Music playlists
> >>
> >>> Am Mittwoch, 24. Januar 2007 22:42 schrieb Troman:
> >>>> ----- Original Message -----
> >>>> From: "Dennis Schridde" <[EMAIL PROTECTED]>
> >>>> To: "Development list" <[email protected]>
> >>>> Sent: Wednesday, January 24, 2007 8:43 PM
> >>>> Subject: Re: [Warzone-dev] Music playlists
> >>>>
> >>>>> Am Mittwoch, 24. Januar 2007 18:46 schrieb Per Inge Mathisen:
> >>>>>> On 1/18/07, Troman <[EMAIL PROTECTED]> wrote:
> >>>>>>> I had some musings about the way this should work. Playlist script
> >>>>>>> interface will be most used by scriptors I assume. I see two main
> >>>>>>> occasions when such an interface might be used:
> >>>>>>>
> >>>>>>> 1) when it is time to interrupt any background music that might be
> >>>>>>> played and kick in some moody piece to create atmosphere, like it
> >>>>>>> is usually done in campaigns.
> >>>>>>>
> >>>>>>> 2) when someone wants to attach a custom playlist to his map, the
> >>>>>>> way it is done with Unreal Tournament maps for example.
> >>>>>>
> >>>>>> Agreed.
> >>>>>>
> >>>>>>> As for the implementation, looks like wz uses 'tracks' to store
> >>>>>>> songs. Track 2 corresponds to menu, track 1 to the in-game music.
> >>>>>>
> >>>>>> I do not think we should let that get in the way of a decent API.
> >>>>>> We can change the way Warzone stores songs, if necessary.
> >>>>
> >>>> Since i'm not the one to program it it's fine with me. ;-)
> >>>>
> >>>>>>> When modder wants his custom playlist to be played when someone
> >>>>>>> is using his map he either loads all songs manually to the user
> >>>>>>> track using scripts, like
> >>>>>>>
> >>>>>>> playlistAddUserSong("mySong1.ogg");
> >>>>>>> playlistAddUserSong("mySong2.ogg");
> >>>>>>
> >>>>>> Sounds good.
> >>>>>>
> >>>>>>> Since this is not the most convenient approach it might be a
> >>>>>>> better idea to load playlist from an external playlist file,
> >>>>>>> which will come with the mod
> >>>>>>
> >>>>>> Well, to me the in-script version above seems more convenient
> >>>>>> than adding yet another file, since the number of songs will
> >>>>>> probably never be high.
>
> I agree, I think it's better to simply stick with creating the playlist
> through scripted functions. Also since I believe the scripts support an
> `#include' style directive, you don't have to clutter all your scripts with
> playlist-append calls.
>
> >>>>>>> In case of a map with custom playlist it is simple, just call
> >>>>>>> something like playlistPlayUserTrack(); from within the scripts
> >>>>>>> (or again we can make wz start playing user track automatically
> >>>>>>> if a map comes with a user playlist) for wz to switch from player
> >>>>>>> playlist to the custom map playlist.
> >>>>>>
> >>>>>> I think starting the script-supplied playlist automatically seems
> >>>>>> like the simpler and better way.
> >>>>
> >>>> What if the user doesn't want any music to be played at the beginning?
> >>>> It's probably better to let the modder decide this.
> >>>
> >>> I think what Per meant is that there should be an initPlaylist function
> >>> in the scripts, which is called upon mission start. If the modder
> >>> doesn't want that, he must not provide that function.
> >>
> >> I don't know how we jumped from playback to initialization. Anyway, for
> >> the initialization of the playlist you just place the necessary code
> >> into the script callback that gets called whenever a map is loaded.
>
> 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.
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.)
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.)

> >>>>>>> In cases when some music must kick in from time to time depending
> >>>>>>> on some in-game conditions it is a bit more complicated.
> >>>>>>
> >>>>>> There are probably two different needs here:
> >>>>>> 1) Scripter wants to play a short song to set the theme of some
> >>>>>> event, then resume the playlist as normal. The new song should then
> >>>>>> not be in the playlist afterwards.
> >>>>>> 2) Scripter wants to change the whole theme of a level by playing
> >>>>>> a new song or songs throughout the remaining time (or until it
> >>>>>> changes again). So we need a way to reset the playlist; then the
> >>>>>> scripter can add the new songs.
> >>>>>>
> >>>>>> So how about an API like this:
> >>>>>> playlistReset() -- deletes existing playlist (eg to remove game
> >>>>>> supplied playlist)
> >>>>>> playlistAdd(song) -- adds song to top of playlist (eg to add to
> >>>>>> game's supplied playlist)
> >>>>>> playlistInterruptWith(song) -- play a song once, then resume
> >>>>>> playing playlist (eg for event)
> >>>>
> >>>> Makes sense to me.
> >>>
> >>> Didn't say that it doesn't to me.
> >>> Just the naming is not my favourite...
> >>> playlistReset -> clearPlaylist
> >>> playlistInteruptWith -> playTrack
> >>> That was my idea... Maybe not ideal, either.
>
> This can be accomplished by my proposal above.
??
> 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.


> >>>>> My proposal:
> >>>>>
> >>>>> Function to set a playlist.
>
> Could by accomplished by multiple playlistAdd(song) calls.
Well, I understood that now. This function would have been a merge of 
createPlaylist and bindPlaylist. (Remember: I came up with those bound 
playlists after thinking about all this.)

> >>>>> Function to immediately play one track.
>
> As explained above.
>
> >>>>> 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...


> >>>>> Function to set playback-modes, like repeat_all, shuffle, fadein,
> >>>>> fadeout, crossfade.
>
> Repeat-all and shuffle shouldn't be to hard to implement.
>
> The fading functions however might be a bit though. This because it would
> basically require you to set AL_GAIN on your playlist ALsource a lot (to
> achieve a good fading resolution). AFAIK OpenAL does not provide any
> feature for fading.
>
> So it's either setting AL_GAIN a lot, or somehow manipulating the decoded
> PCM data stream.
>
> As for cross fading. This would basically require two ALsources on the
> moment of switching songs. (You can only send one PCM stream through an
> ALsource at a time.) Or again manipulating the PCM stream by mixing on the
> software level. (Rather than using the hardware mixer)
Actually I didn't think of that yet...

> >>> Those effects (not shuffle, but .*fade.*) would also affect
> >>> playTrack(). If the modder wants something different, he can switch
> >>> modes before and after his custom track. (Reacting to events.)
> >>>
> >>>> This all can surely be usefull to the end user/scriptor. Crossfades
> >>>> for 'insertations' especially in campaigns etc.
> >>>>
> >>>>> Clearing the playlist is simply supplying an empty playlist.
> >>>>> I don't think there is any need to dynamically attach a track to the
> >>>>> playlist, am I correct? Why would one attach a song if he doesn't
> >>>>> know when it will be played...
> >>>>
> >>>> You never know what's going on inside of a modder's head, it doesn't
> >>>> take much affort to provide this functionality, besides I don't see
> >>>> how else we would want to re-fill the list (see below).
> >>>
> >>> If there is technically no other way, yes. In my idea you could re-fill
> >>> the list simply by setting the playlist to a list of different songs...
> >>> But addTrack should have a switch so you can choose whether to append
> >>> to the front or the back... (Or maybe better 2 functions addTrackFront
> >>> addTrackBack, or appendTrack prependTrack, or similarly named.)
> >>>
> >>> I just got the idea of Open*L style functions... OMG... crazy...
> >>> createPlaylist(Playlist*); // New, empty playlist
> >>> deletePlaylist(Playlist*); // Trash it, mark pointer invalid
> >>> bindPlaylist(Playlist*); // Switch to another playlist
> >>> addTrack(Playlist*,Track*); // Append Track
>
> Wel the functions on their own look quite good to me.
> Their prototypes however... Let's just say that I don't like the idea of
> passing pointers into the scripting engine.
This was _not_ a proposal for the scripting engine, but for the C-API...
The scripting engine would get some integer IDs or similar...

> >>> 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.

> >>> bindPlaylist:
> >>> Set sound engine's nextTrack pointer to 1st item of the given list, and
> >>> advise it to skipTrack() so it plays nextTrack.
> >>>
> >>> The linked list would perhaps become a bit unhandy when it comes to
> >>> shuffling and repeating, but it seems very handy when binding, adding
> >>> or switching to the next track...
> >>>
> >>> What do you think about this? Opinions, objections?
> >>
> >> I don't know if linked list is best suitable for this or about other
> >> implementation details but the idea itself sounds good, this approach is
> >> more flexible than current one. For just the in-game playlists it may be
> >> too much, but could be usefull when scripts get involved.
> >
> > I just don't know what else could be used. There are no dynamic arrays in
> > C, at least none that I know of. And I don't have another idea how
> > several dynamic-sized playlists could be handled. (I am lacking
> > experience and probably I didn't read my C book till the end.)
>
> 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...

> > 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.


> 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.

> >>>>> 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...

> >>>> Any particular reason not to use playlistSetMode() instead of
> >>>> WZSound_setPlaylistMode()? It's shorter while preserving the same
> >>>> meaning.
> >>>
> >>> For the scripts I don't care.
> >>
> >> For the scripts, yes.
>
> I think scripts should indeed have functions without the WZSound in front
> of it.
>
> >>> For the code I think we should develop some unique and sane naming
> >>> convention to prevent name clashes and provide a clear and consistent
> >>> API. That's why I came up with WZSound_. Other engine (-> lib/) parts
> >>> might be called WZScript, WZIvis  (what does ivis actually mean/stand
> >>> for?) or WZGrahics...
>
> In the codebase itself I really like this idea.
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.

> >>>>> Additionally I would sent following events to the scripts (and over
> >>>>> the internal event-bus), namings are currently very bad:
> >>>>> playlist_stop
> >>>>> playlist_resume
> >>>>> playlist_nextTrack
> >>>>> playlist_customTrack
> >>>>> playlist_customTrackEnd
> >>>>> playlist_modeChange
> >>>>> playlist_new
> >>>>> playlist_end
> >>>>>
> >>>>> --Dennis
> >>>>
> >>>> Script events would be usefull. Those would end up being named
> >>>> CALL_PLAYLISTEND, CALL_SONGEND etc following wz convention. But those
> >>>> are details, provide me playlist functionality I'll take care of the
> >>>> rest, probably not until mid february though.
> >>>
> >>> 2.1 won't be released in February and probably not in March or anytime
> >>> soon. So this currently doesn't matter that much. ;)
>
> In that case lets haul the code over entirely ;-).
>
> >>>> PS: geez am I the only one having trouble replying to attached files?
> >>>
> >>> Apparently: Yes...
> >>
> >> Wouldn't have asked if it was apparent. I was refering to those '>'
> >> markers actually. Don't see a way how to add them with outlook express,
> >> which forces me to make a small detour.
> >
> > Outlook doesn't give you those '>' if you press reply on a mail which has
> > an attached file???
>
> Of course I can advise you to take and use Thunderbird instead ;-) . It's
> more powerful than Outlook (e.g. in case of low level access, mem
> footprint, etc).
>
> PS I'm not @ home right now, therefore I haven't signed this message with
> GPG/PGP.

Attachment: pgp3SnbWyziNf.pgp
Description: PGP signature

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

Reply via email to