Open emoon opened 3 years ago
That is a nice idea! I have started to do this in the multi-gbs branch which does not compile yet. I'll just extract everything into a struct as you suggested and see where it gets us :-) Full thread-safety might still be a long way to go because then all functions would need to be fully reentrant - I don't know if we can guarantee this. But running everything over a gbhw handle like you suggested should work – it's just a bit of refactoring work.
Checklist for things that have come up:
gbhw.c:gb_change_level()
- the impulse itself is constant (from compile-time generated impulse.h
) and the impulse buffer is part of struct gbhw
which is part of struct gbs
struct gbhw*
& co in the libgbs interface? will this stay compatible if we have internal changes in the structs? if not, how do we tackle this instead? ==> forward declare structs, see below
struct gbhw *gbhw
into struct gbhw *const gbhw
? same for gbs and gbcpu
xxx_handle_init()
functions
xxx_init_struct()
it isyou don't need to expose the internals really, you can just forward declare struct gbhw;
in the gbs.h
and it will just take the pointer in each function so that pointer will just be "passed down" to specific gbhw_<func>
that includes the real header with the internal info.
An alternative to bump to 1.0 is to do something like this
inline void gbhw_setrate(int rate) { gbhw_state_setrate(&g_global_state, rate); }
Now the old API can still work and it makes it possible for people to transition to the gbhw_state_*
API instead, but up to you :) Using the old API of course isn't thread safe, but it would still work with compiling the code and run as before.
I foresee some problems with API stability and forward declaration of structs (currently code outside of gbhw accesses the channel data directly, this will probably need some new functions). So for now I created the new issue #42 to address the API stability. This issue will just focus on the changes to use multiple gbhw instances at the same time.
The new interface that basically encapsulates everything inside the struct gbs
works.
As keep piling up more and more refactorings in the multi-lib
branch, I'll just merge that branch to master if there are no objections against it in the near future ;-)
As of now the libgbs interface becomes incompatible, but want to tackle that separately in issue #42.
Perhaps it is not bad that I rename all the external gbs_*
functions – that way we can easily build a backwards compatible layer to the old interface ;-)
The branch has been merged to master. You can try it, but as already discussed the API has changed and will change again, it is neither stabilized nor finalized yet.
Cool. Thanks!
btw:
struct gbs*
handle.static
is const
.This would mean that we are thread-safe and re-entrant now, right? (unless I missed a variable)
yeah, as long as the code only works with it's own owned data and doesn't modify global state it's all fine.
To validate this is true the best way would be to write a test for it. The test could look something like this:
// singe threaded test
songs = ["song1.gbs", "song2.gbs", "song3.gbs"];
hashes_single = [];
hashes_multi = [];
for (song in songs) hashes_single[song] = calc_hash(render_song(song));
// multi test
for (song in songs) {
spawn_thread( hashes_multi[song] = calc_hash(render_song(song)) );
}
// wait all threads
...
// compare hashes between single and multi
...
I had something in mind along these lines. We currently only have one demo song – so either we would have to play it multiple times (which might hide some errors if we're unlucky) or we perhaps should write three very simple demo songs. Perhaps playing some simple scales would be enough. This would be a nice side project, I never wrote a GBS before :) Having a demo song in source form (assembly or C) in here would be a nice form of additional documentation of the GBS format I think.
Hi,
First of all thanks for a great library!
I wonder if there are any plans on making the code thread-safe? My use case is that I want to support play more than one song at a time (examples being cross fading, multi decode of many files at the same time, etc)
The current problem is that esp
gbhw.c
has lots of global variables. On way to solve this would be to setup a "state object" as the first parameter to allgbhw_
functions could take that instead of using the global variables. That way several threads can have their own "hardware" without conflicting with each-other