----- Original Message ----- From: "Troman" <[EMAIL PROTECTED]>
To: "Troman" <[EMAIL PROTECTED]>
Sent: Thursday, January 25, 2007 5:57 PM
Subject: temp


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

Ditto. I don't know why we would want to force playback, let the modder decide.

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

Almost exactly what I had in mind. Seems to be very flexible to me.


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.


Scripts should be notified about all playlists/songs events, not only those created by scripts. For that matter I mentioned handles in the first post. After the creation of playlists and/or songs some handles could be returned to the scripts. Then when playlistFinished/songFinished callbacks occur they would return playlist/song ID. I don't think we can harm the modder in any way.



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

Why not? That's the way most of the scripting stuff works right now. Scripts currently work with a lot of pointers passed from WZ, although from the scriptor's point of view there's no difference between integers/bools or pointers to some internal wz structures. Not that it really matters to me. If we just work with integer ids, that would mean we have less different types to define for scripts (I don't really like the idea of flooding scripts with dozens of new types, unless really needed, but i'm not yet sure what would be optimal for us).

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

While surely not as elegant as dynamic arrays we can as well just use fixed arrays if those are only used to hold pointers to playlists, to be honest I doubt anyone would want more than, say, 20 playlists at a time (i'm being rather generous).


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


Sure, best way to solve this is to provide constants predefined by wz, works like a charm.


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

Might as well do this someday, for now I think I'll give Outlook a try and see if it offers enough functionality (using Outlook Express right now).

BTW why don't we just use forums for such discussions? This starts to look a bit awkward to me. Maybe we can ask Kamaze to set up some protected area for the developers and those participating in the mailinglist discussion? Personally i'd also be fine with a public forum, not sure if this would work well though.


PS I'm not @ home right now, therefore I haven't signed this message with
GPG/PGP.



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

Reply via email to