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: <warzone-dev@gna.org>
>> 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" <warzone-dev@gna.org>
>>>> 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.

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

>>>>> My proposal:
>>>>> 
>>>>> Function to set a playlist.
Could by accomplished by multiple playlistAdd(song) calls.

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

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

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

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

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

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

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?

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

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

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

-- 
Giel


_______________________________________________
Warzone-dev mailing list
Warzone-dev@gna.org
https://mail.gna.org/listinfo/warzone-dev

Reply via email to