Am Freitag, 26. Januar 2007 schrieb Giel van Schijndel: > 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. I didn't suggest something different. ;)
> > 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.
Sorry. Got lazy without codecompletion...
> >>>>> 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).
Actually I thought WZ has a resource-handler. Don't know if that's true, but I
guess it has something more to offer than just some malloc wrappers...
> >> 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.
Or use the one from FreeCiv. ;)
> >>> 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).
So you need a front and a backbuffer to decode while playing? Didn't know
that... Thought you could dynamically append data to the buffer or similar.
> >> 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.
enum {a=1,b=2,c=4};
a+b \not\in enum
That's how compilers handle this if they are strict. You'd have to add a lot
of sets for every possible combination...
(Sorry for TeXing)
And actually I don't know how #defines overun large pieces of the code, or how
they would not be limited to the required parts of the code.
> >>>>>>> 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.
I said that after Troman pointed it out that it would be more convenient...
> Although I do think it would be
> better if we'd use something like defines or constants instead.
Troman agrees with you. I don't know of what the scripting engine is capable.
> > 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.
--Dennis
pgpMtrKodlA45.pgp
Description: PGP signature
_______________________________________________ Warzone-dev mailing list [email protected] https://mail.gna.org/listinfo/warzone-dev
