Yo Allegators!
As the thread title suggests, I was wondering why the 'extra' userdata pointer in the ALLEGRO_AUDIO_STREAM structure does not have an API to be accessed/used.
I've scoured through the current stream implementations and ALL and EACH of them use the extra pointer to pass a pointer to the file structure (being it WAV, OGG, IT, MOD, whatever), which comes in handy when usign the feeder thread.
I was looking into implementing a stream version for a WildMidi sample Loader, and of course I'd like to take advantage of threading in Allegro to have an automatic feeding mechanism, but unless I explicitly ADD a wildmidi loader to Allegro itself, I can't access the 'extra' pointer, thus I can't have the stream internally reference the filedata which would be useful to pass to a dedicated loader thread.
Premise: I do not want to add a wildmidi loader to Allegro due to:
- Wildmidi being LGPL and thus not very welcome into allegro dependency.
- being a softsynth, it depends on GUS compatible patches and an external cfg file...and as such not 'self contained' enough for this task (IMO).
So I'd like to do that "externally", but I do WANT to be able to al_register_audio_stream_loader my loading functions (just like my load_sample functions)
This forces me on (as far as I can tell right now) two possible paths:
explicitly pass around the wildmidi file data structure in my stream manager; problem: I drop the possibility to register my loader into Allegro interface (since it then has incompatible signature).
create a static container which holds the information for all the open streams and can thus be accessed both from the loader and the feeder thread; problem: an unwanted layer of management and check for data races and so on....
I was looking for some advice on which of these should be my choice...which can very well be 'neither of the two'
...and maybe (!) a dev word about adding an API like al_set/get_audio_stream_userdata(ALLEGRO_AUDIO_STREAM* stream, void* extra) to the Allegro_Audio addon.
The latter seems to me that could be an easy addition and should cause no harm.
My very weakness here is that I do not know squat about proper threading and I'm sure I might be missing something obvious.
Thanks for any feedback.
That seems like a reasonable addition. Without thinking too much of it, it might be nice to also specify a destructor alongside this pointer?
There is another, sort of related, thing I just want to put out there. One weakness of the current audio addon is that it conflates two meanings of the word 'stream'. The first, is streaming from a file: i.e. on-demand loading/generating audio. The second, is slowly feeding audio data to a mixer. The second is in principle supported, but the first is part of the internal API (every implementation of a file-backed audio stream has an implementation of reading from a file on demand). It'd be nice to make it user-accessible.
I didn't think about a destructor, which could come in handy after all when destroying the stream.
One question arises thou: internally the struct has a member void *extra, which is currently used and I assumed that IF allocated (i.e. != NULL ) would have al_free called on it upon destruction.
Were I wrong assuming it?
Right now I've added the two functions but I am merely adding the 'extra' as a pointer to a WM_FILE_DATA struct that very much resembles WAVFILE, FLACFILE, etc...so a dtor is not strictly needed. I'll try to experiment a bit, if you like I can make a PR to have the code availble for review, though it's DEAD SIMPLE.
About your observation, I tend to agree that exposing the common interface for on-demand load could be useful, along with being able to register new handlers just like the loader....but I admit I haben't yet tooled around with the addon enough to have a well-informed opinion; gut feeling is that's a sensible proposal.
EDIT: I just realized that I can't access also the stream mutex with the API...damn...
How should I go then for a proper feeder thread?
Without thinking too much of it, it might be nice to also specify a destructor alongside this pointer?
I've dabbled a bit with the two functions, could you please explain me how should I handle the destructor passign along and such?
Is there something like _al_register_destructor internal function? (I ask cause none is documented).
I've succeeded into expanding the API with:
al_get_audio_stream_userdata
al_set_audio_stream_userdata
al_get_audio_stream_mutex
and implemented a WildMidi loader which can be registered into Allegro interface and auto-feeds the stream.
It can be found here for peer-review, even thou I fear I'll be an embarrassment to myself
Anyway I ran into some problems, that persist and that shed some light on what Siegelord wrote above (I didn't understand fully at the time, I guess).
The stream internal are quite elaborated and passing a userdata pointer to manage the extras seems inefficient and incomplete.
For example, I correctly register my functions into Allegro interface through al_load_audio_stream and it starts the auto-feed thread, BUT I don't have means to signal the thread itself to stop if I call al_destroy_audio_stream
In the test executable it's not a problem but I know this is unacceptable, I will have to find a way to register an *extra destructor that handles the signal for me (by the way, if anybody could suggest HOW, as I asked above, I'd appreciate ).
Seems a waste, since al_destroy_audio_stream ALREADY does that for the internals.
I think that the stream API might benefit from a larger exposition of the stream's structure, at least for the feed thread and such.