Re: [fluid-dev] Making MIDI player read from a buffer
Thanks very much David. It was great working with you throughout the concept and implementation of this new feature. Also the adding an example in the documentation and for providing easy links > in the email above was much appreciated! > No problem. I love Launchpad. I really recommend anyone who is working on a long patch against SVN use Bazaar -- it makes it very easy to commit your patch in stages and merge in changes from trunk as they come through, and is compatible with SVN. I added out-of-memory checks on fluid_player_add and fluid_player_add_mem - > I thought it made sense at least for the potentially big allocation of the > midi file. I also swapped a row or two - some compilers (and the C > standard?) are a little picky on mixing declarations with statements. Ah, good catch. It's definitely important to check that the big copy malloc succeeds. As for mixing declarations with statements: It is allowed by the C99 standard, but not any earlier standard. I prefer code which is pre-C99 compatible for maximum portability, so it's good you fixed this (apparently GCC at least doesn't complain about it by default). Cheers! Matt ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
On 2011-02-20 07:27, Matt Giuca wrote: I have updated the midi-buffer branch with the previous two suggestions: 1. fluid_player_add_mem now copies the buffer before it stores it, so the caller can now free it immediately (and it is now the caller's responsibility to free). 2. Internally, fluid_midi_file now uses int buf_len and buf_pos instead of pointers. This just makes things a little easier to think about. As usual, I currently have it in a Bazaar branch in Launchpad here: https://code.launchpad.net/~mgiuca/fluidsynth/midi-buffer use: bzr branch lp:~mgiuca/fluidsynth/midi-buffer The full patch against the trunk (SVN r406) is viewable and downloadable here: http://bazaar.launchpad.net/~mgiuca/fluidsynth/midi-buffer/revision/360?compare_revid=336.1.14 The patch against my previous draft is here: http://bazaar.launchpad.net/~mgiuca/fluidsynth/midi-buffer/revision/360?compare_revid=337 The example in the documentation has been updated to reflect the new usage model. It should be ready to merge now. The full patch can be downloaded here: http://bazaar.launchpad.net/~mgiuca/fluidsynth/midi-buffer/diff/360/336.1.14 Thank you for your contribution - it has been merged! Also the adding an example in the documentation and for providing easy links in the email above was much appreciated! I added out-of-memory checks on fluid_player_add and fluid_player_add_mem - I thought it made sense at least for the potentially big allocation of the midi file. I also swapped a row or two - some compilers (and the C standard?) are a little picky on mixing declarations with statements. // David ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
I have updated the midi-buffer branch with the previous two suggestions: 1. fluid_player_add_mem now copies the buffer before it stores it, so the caller can now free it immediately (and it is now the caller's responsibility to free). 2. Internally, fluid_midi_file now uses int buf_len and buf_pos instead of pointers. This just makes things a little easier to think about. As usual, I currently have it in a Bazaar branch in Launchpad here: https://code.launchpad.net/~mgiuca/fluidsynth/midi-buffer use: bzr branch lp:~mgiuca/fluidsynth/midi-buffer The full patch against the trunk (SVN r406) is viewable and downloadable here: http://bazaar.launchpad.net/~mgiuca/fluidsynth/midi-buffer/revision/360?compare_revid=336.1.14 The patch against my previous draft is here: http://bazaar.launchpad.net/~mgiuca/fluidsynth/midi-buffer/revision/360?compare_revid=337 The example in the documentation has been updated to reflect the new usage model. It should be ready to merge now. The full patch can be downloaded here: http://bazaar.launchpad.net/~mgiuca/fluidsynth/midi-buffer/diff/360/336.1.14 Matt ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
Hi David, In response to your post here: http://lists.nongnu.org/archive/html/fluid-dev/2011-01/msg3.html > Well, for the memory allocation issue it sounds like we both are leaning > towards #5 as in copying the memory. I don't think the > inefficiency is an issue and it gives FS the most options to change later. Agreed. OK. I will change the code so it copies the buffer, and the user can free it immediately as soon as fluid_player_add_mem returns. > As for the rest of the patch - well, haven't gone through it letter by letter > but it looks good to me. Assuming that it works, I think you've > done a good job with it! Thanks! If you (or anyone) wants to test it, I have added a code snippet to the front page of the documentation which includes a small sample in-memory MIDI file. I don't know what more-rigorous testing we could use (I have tried it on some full-size MIDI files and it works). Is there a test suite I should add some cases for? > A question about the fluid_midi_file struct: > > typedef struct { > const char* buffer; /* Entire contents of MIDI file (borrowed) */ > const char* buf_end; /* One-past-end of contents buffer */ > const char* buf_ptr; /* Current read position in contents buffer */ > int eof; /* The "end of file" condition */ > int running_status; > int c; > int type; > int dtime; > } fluid_midi_file; > > First, is the "eof" variable necessary or is that the same as buf_ptr >= > buf_end ? Yes it is necessary to have a separate variable. With the first four fields (buffer, buf_end, buf_ptr and eof), I am trying to emulate the stdio FILE type as closely as possible, since the original code worked directly with a FILE*. I have provided a new "in-memory" version of each of the stdio file operations, such as fgetc, fread, fseek and feof, and tried to implement the same semantics as the man pages for those functions. I remember being confused by this as well. The way feof works is not to check if the *next* fgetc operation would fail. It "tests the end-of-file indicator" -- checking whether the *previous* fgetc operation failed. This end-of-file indicator is set by any file operation which attempts to read past the EOF. A getc of the last byte in a file does not set the indicator; only a subsequent getc would set it. Therefore, it implies some state beyond "what is the position in the file?" You also need to know "have any previous operations failed?" This is an important distinction in its usage at the end of fluid_midi_file_read_track. There is a call to fluid_midi_file_eof (in the unpatched code, a call to feof), which errors out in the EOF case. If it were merely checking for buf_ptr >= buf_end, it would raise an error for the last track in the file, because the last byte of the file has been read at that point. We need it to only be an error if the file caused any operation to read too far past the end. This is summarised in a comment in fluid_midi_file_eof: > /* Note: This does not simply test whether the file read pointer is past > * the end of the file. It mimics the behaviour of feof by actually > * testing the stateful EOF condition, which is set to TRUE if getc or > * fread have attempted to read past the end (but not if they have > * precisely reached the end), but reset to FALSE upon a successful seek. > */ > Second, I would probably have done "int buf_length" and "int buf_pos" (as > indices to the buffer array) instead of buf_end and buf_ptr, > but I guess that's mostly a matter of taste. Nothing to reject a patch for. True. I agree with this. It makes it clear that there is only one buffer, not three, and briefly looking at the code, would probably simplify it in several places. I will make this change at the same time as I do the memory allocation change. Matt ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
> Many thanks for this. I never did find the time to finish up my > SDL_mixer patch and send it upstream because life has taken over but > this looks great. Tell me about it ... took a long time to get this buffer patch done as well. > I look forward to cutting my patch in half. :) > Well the one problem is that if you depend upon midi-buffers then your SDL_mixer patch will have to depend upon a brand new release of FluidSynth. It will take awhile before that's mainstream enough to rely on (i.e., included as the official packaged version of Fluid in all the major distros). ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
On Sat, 4 Dec 2010 13:55:51 +1100 Matt Giuca wrote: > I have completed an initial cut at the implementation of the new > fluid_player_add_mem API call, which lets you add a MIDI file to the > playlist from a buffer in memory, rather than a filename. Many thanks for this. I never did find the time to finish up my SDL_mixer patch and send it upstream because life has taken over but this looks great. I look forward to cutting my patch in half. :) James ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
Hi guys, I have completed an initial cut at the implementation of the new fluid_player_add_mem API call, which lets you add a MIDI file to the playlist from a buffer in memory, rather than a filename. This required extensive re-architecting of the internal mechanism for loading files. The old fluid_player_add no longer reads a file in a few bytes at a time -- it allocates a buffer for the whole file, reads it in, then uses the new memory based loader. I currently have it in a Bazaar branch in Launchpad here: https://code.launchpad.net/~mgiuca/fluidsynth/midi-buffer use: bzr branch lp:~mgiuca/fluidsynth/midi-buffer The full patch against the trunk (SVN r393) is viewable and downloadable here: http://bazaar.launchpad.net/~mgiuca/fluidsynth/midi-buffer/revision/356?compare_revid=336.1.3 Note that I have added a new section with a full example to the documentation: http://bazaar.launchpad.net/~mgiuca/fluidsynth/midi-buffer/revision/352 If anyone is interested, try running this example and see if there are any problems. It isn't ready to merge yet, as there is still a bit of a discussion to be had about garbage collection. To recap, we had five proposals for how the user code and our code will allocate and free the buffer: 1. Stealing from client-malloc; fluid will call free(). Won't work with different allocators other than malloc. 2. Stealing from client-fluid_alloc; fluid will call fluid_free(). At least it lets fluid control the allocator. 3. Borrowing; fluid will not free memory. Requires complicated memory management in the client. 4. Borrowing, with a "destructor" callback. Lets the client control allocation and freeing, and can easily simulate #1 or #2. 5. Copying. Client must free, but can do it right away. Easiest method, but inefficient. I was leaning towards #2 (client allocs, fluid frees). But having written that example, it's pretty annoying. I'm now leaning toward's David's suggestion, #5, in which fluid_player_add_mem simply copies the buffer immediately, and the client is able to free it immediately. Note that in my example, I was forced to malloc and copy the buffer; this copying approach would let me simply send a pointer to the global buffer in to FluidSynth. Matt Giuca ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
I have started making the changes (the major internal change to fluid_midi is done; it now loads the file to memory at the start and does all the parsing from the memory buffer). It currently "owns" the pointer (garbage collection choice #2), but we can discuss that further. The code is in a branch on Launchpad (in Bazaar) here: https://code.launchpad.net/~mgiuca/fluidsynth/midi-buffer Someone had very foresightfully abstracted all of the libc file operations into fluid_file_* operations, making this job pretty damn easy. :) Matt ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
On 10/19/2010 12:27 PM, David Henningsson wrote: On 2010-10-19 09:47, Graham Wykes wrote: Would there be value in looking at the patch than Jim Henry mentioned (given that it has been effectively tested for many years by hundreds of users of Miditzer) to see whether it is compatible with the current code. Good idea, can we have someone post it here? I did a quick search but couldn't find anything. With any luck it may have fluid_synth_handle_porridge_event already implemented ;-) Eww, don't want to listen to the sound after that ;-) The patch I mentioned was applied to FluidSynth 1.0.8. I can say with pretty good confidence that the patch has to be redone to work with the changes that have been made to FluidSynth since then. I would take the testing by Miditzer use with a grain of salt because that use is tightly controlled and consistent amongst the hundreds of users. So there isn't much breadth in that testing. I have tried to revise and apply the Frappiat patches to FluidSynth 1.1.1 and I got as far as adding all the DLL entries and some of the easier functions so that the Miditzer community could test the core functionality of the new version of FluidSynth. However, I didn't manage to add the main function of returning the MIDI messages to the caller. I will send a copy of what I have to Pedro and anyone else who wants a copy of this for what it's worth. Jim Henry ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
> > So to summarize, the possible approaches are: >> 1. Stealing from client-malloc; fluid will call free(). Won't work with >> different allocators other than malloc. >> 2. Stealing from client-fluid_alloc; fluid will call fluid_free(). At >> least it lets fluid control the allocator. >> 3. Borrowing; fluid will not free memory. Requires complicated memory >> management in the client. >> 4. Borrowing, with a "destructor" callback. Lets the client control >> allocation and freeing, and can easily simulate #1 or #2. >> 5. Copying. Client must free, but can do it right away. Easiest method, >> but inefficient. >> > > Good summary. I think the reason I thought of 5 as the most flexible one > would be because if we ever changed it to do the parsing at add_mem time, we > would just skip the copy, and no additional memory management would be > necessary. > Oh I see. Well if we went with #2 it would still be easy to extend it to do parsing at "add time"; we would just make it free the memory immediately. The only problem is it would now be inefficient if a client *did* do a copy. Also the interface ("it reads from the buffer then frees the buffer for some reason") would no longer make much sense. But it wouldn't break clients, at least. I suppose the question is then, is there a serious intent (not now, but in the future) to modify the behaviour so it parses the MIDI file at "add time"? If so, #5 makes the most sense. If not, I think #2 still makes the most sense. Note that initially your concern was about having multiple MIDI files in memory at a time (which is why you suggested the compromise of still storing filenames at "add time" until "play time" when the full load-and-parse is done). It's probably not too big of a concern given that I've never seen a MIDI file above 1MB, but something to consider. The decision won't really affect the implementation (we can easily change garbage collection strategies after this patch has been written), it's just something we need to decide on before committing to the trunk, as it will affect the clients. ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
On Tuesday 19 October 2010, David Henningsson wrote: > If you feel that the current API needs incompatible > > changes, then this feature should go in a library version 2. That's all. Not a > > big deal, this is going to happen sooner or later. > > If you're talking about dropping backwards compatibility, then that is a > big deal IMO. We might come to a point where we believe it is necessary, > but I don't see it coming right now. Of course, something like that needs a solid justification. But there is a limit of what you can fix without breaking compatibility. And if we reach that limit, finding good reasons to bump the sacred soversion number, I would be glad because this means that our project is alive, growing well, and maturing. Regards, Pedro ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
On Tuesday 19 October 2010, Matt Giuca wrote: > ...as long as it doesn't break anything else, which is the hard part. > > I think he meant nobody has the right to stop you implementing it in your > own private branch. It's convincing others to accept them that's the hard > part :) Which I've learned from other open source projects. If a code branch is not accepted by the original project, but the developer thinks it is worth enough, the usual outcome in free software projects is to create a fork [1]. Sometimes, the forked code and the original trunk coexist for some time until one or both die, or get finally merged again. It happened in GCC, with the 'egcs' fork, and also in the projects Compiz, Beryl and Compiz Fusion. This is the jungle, brother. Regards, Pedro [1] http://en.wikipedia.org/wiki/Fork_%28software_development%29 ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
On Tuesday 19 October 2010, Jim Henry wrote: > Pedro, > > It sounds like you are suggesting a feature that the Miditzer virtual > organ uses. A number of years ago Sebastian Frippiat suggested extending > FluidSynth so that the MIDI Player would pass the MIDI events to the > caller rather than playing them. You mean these patches, right? http://www.mail-archive.com/fluid-dev@nongnu.org/msg00262.html Yes, this strategy may allow to manipulate the events *before* playing them in some cases, or *instead of* playing the events in other cases. This is part of the additional functionality I need for the KMid backend. The tempo factor is also in my agenda. The velocity factor is not, because volume changes should be done using the CC#7 (main volume) controller instead. And I also need a pitch modifier (MIDI note number +/- 12 semitones) but this can be implemented using the events callback. > At the time there was no interest in > his proposal. I think this was in part because he wanted just to use > FluidSynth as a MIDI file reader and it was felt that was not within the > scope of FluidSynth's purpose. He did post patches for doing this. We > picked up those patches for the Miditzer and they are in the version of > FluidSynth used with the Miditzer. Nice, so you have tested this well. May I have your modified source code of FluidSynth, please? > As Pedro suggests, the Miditzer takes MIDI input, including the input > from the FluidSynth MIDI file reader, and vigorously manipulates the > MIDI data before sending it to FluidSynth to be realized in order to > create the organ performance paradigm which just doesn't fit within the > standard MIDI specification. (By that I mean there is no way to fully > encode the performance of an organ according to the MIDI specification.) > > If there is now interest in extending the FluidSynth MIDI file player to > send the MIDI messages to the caller for processing rather than playing > them, I certainly support such an effort. Yes. My plan include some more things. First, I want to parse all SMF meta- events, including all kind of text events. Most of these events are meaningless for the synthesizer, but can very important for applications. For instance, to display song lyrics. The song contents needs to be exposed to the application client, either using another callback function hooked inside the parser that would be called for some types of events, or exposing the whole song structure to the clients after the song has been parsed, with an API to enumerate the tracks, events on the tracks, and so on. It would be nice to have a mechanism to modify, delete and insert events, or even new tracks, and also supporting "user events" defined by the client applications. This would be like the MIDI part of the AudioToolbox framework in MacOSX. Regards, Pedro ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
On 2010-10-19 11:21, Matt Giuca wrote: [] I've cut down the rest of the text, just because I don't think there is more to add to it. So to summarize, the possible approaches are: 1. Stealing from client-malloc; fluid will call free(). Won't work with different allocators other than malloc. 2. Stealing from client-fluid_alloc; fluid will call fluid_free(). At least it lets fluid control the allocator. 3. Borrowing; fluid will not free memory. Requires complicated memory management in the client. 4. Borrowing, with a "destructor" callback. Lets the client control allocation and freeing, and can easily simulate #1 or #2. 5. Copying. Client must free, but can do it right away. Easiest method, but inefficient. Good summary. I think the reason I thought of 5 as the most flexible one would be because if we ever changed it to do the parsing at add_mem time, we would just skip the copy, and no additional memory management would be necessary. But I don't mind additional opinions here. Anyone? // David ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
On 2010-10-19 09:47, Graham Wykes wrote: On 19/10/2010, at 6:07 PM, David Henningsson wrote: On 2010-10-19 00:02, Pedro Lopez-Cabanillas wrote: On Monday 18 October 2010, Matt Giuca wrote: So my questions for any interested observers (especially FluidSynth developers): 1. Is this feature worth implementing at all? If you are motivated to do this work, then go ahead. Nobody has any right to stop you of adding an improvement that you want to implement, and you believe that it is valuable. ...as long as it doesn't break anything else, which is the hard part. I don't want to comment about the implementation details in your proposal, either. If you feel that the current API needs incompatible changes, then this feature should go in a library version 2. That's all. Not a big deal, this is going to happen sooner or later. If you're talking about dropping backwards compatibility, then that is a big deal IMO. We might come to a point where we believe it is necessary, but I don't see it coming right now. It would mean all distros shipping with two FS library versions, then someone finds a bug in the old one, and we only support the new one, and so on... There was a proposal by Antoine Schmitt in this mailing list some time ago about reimplementing the MIDI player using the sequencer API, in a similar way of James' SDL patches. That may work if some problems are solved first: the current MIDI parser is incomplete, and the sequencer lacks some features. If this refactoring is going to happen some day it would be complementary, not redundant, WRT your feature of reading MIDI data from a buffer instead of disk files. Talking about my personal interests, MIDI applications often need to parse MIDI files to manipulate MIDI events (sometimes interactively) before sending the events to the MIDI sequencer engine. For instance, to change the instrument maps of melodic and percussion instruments (MIDI mappers), or to manipulate controller events (i.e. MIDI volume), muting MIDI channels, transposing MIDI notes on melodic channels, synchronous display of SMF embedded song lyrics, and so on. All these functions belong not only to MIDI editors, but also to players like KMid (http://kmid2.sourceforge.net). This program has backends using the OS native sequencer services for Linux, Windows and MacOSX, and I would like to implement a pure FluidSynth backend. To do that, FluidSynth needs some new features for manipulating the playlists, but more important: a new mechanism in the MIDI player to route selected events to the client application, that may change them before playing. Opinions are welcome. I think inserting a hook would be quite easy. fluid_synth_handle_midi_event is called from fluid_track_send_events, and it seems like that would be a good place to insert the hook - let the fluid_track_send_events call a user-specified callback, then let the user-specified callback call fluid_synth_handle_midi_event, or call some other fluid_synth_* function, or write to the console, or eat porridge [1], etc. // David [1] This proposal was added by my unconscious, subtly trying to make me go and have breakfast soon. ;-) ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev Would there be value in looking at the patch than Jim Henry mentioned (given that it has been effectively tested for many years by hundreds of users of Miditzer) to see whether it is compatible with the current code. Good idea, can we have someone post it here? I did a quick search but couldn't find anything. With any luck it may have fluid_synth_handle_porridge_event already implemented ;-) Eww, don't want to listen to the sound after that ;-) ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
> > We could also copy the memory. While copying memory around is inoptimal, > that might be a secondary concern. At least that would give us the most > future flexibility. Oh yeah, that was my other thought. I think the problem with that is that again, in almost all cases I can think of, you'll allocate the memory *just*to load and then pass to FluidSynth, which would then in turn allocate the memory *again* just to copy it and then you'll immediately free the original memory. I don't see how it gives us future flexibility any more than the other approaches -- either way once the decision is made, clients will be locked in to one particular garbage collection strategy or another (in this case, clients will be freeing the memory as soon as it's passed to FluidSynth, which makes their code incompatible with the stealing or borrowing approaches). I was about to suggest (and I see you suggested below as well) a fluid_alloc function which lets you allocate the memory in a fluid-approved way, which could then automatically be freed. This would be equivalent to the "copying" approach (in that Fluid owns the pointer), except that the client has control of the memory initialisation. If you had a buffer which is not fluid_alloc-allocated, you could do the copy yourself (which would be no more expensive than if fluid_player_add_mem did a copy). So to summarize, the possible approaches are: 1. Stealing from client-malloc; fluid will call free(). Won't work with different allocators other than malloc. 2. Stealing from client-fluid_alloc; fluid will call fluid_free(). At least it lets fluid control the allocator. 3. Borrowing; fluid will not free memory. Requires complicated memory management in the client. 4. Borrowing, with a "destructor" callback. Lets the client control allocation and freeing, and can easily simulate #1 or #2. 5. Copying. Client must free, but can do it right away. Easiest method, but inefficient. I think I prefer #2, because it gives maximum power to the client, is efficient and doesn't require that they do memory management. #4 is even more powerful, but a bit complicated an API call. If so, we should probably also add fluid_malloc / fluid_realloc / fluid_free > as API additions to make sure the same memory allocator is used. After all, > in a future version of FS, we might want to switch memory allocator, write > our own for some reason, etc. Yep. OK so I'd probably advocate writing them. Maybe even a void* fluid_copy_alloc(void* buffer, size_t length), which is short-hand for fluid_malloc followed memcpy. One hard part of FluidSynth is that it has so many use cases, and we can't > fail a single one of them. What we can't do good enough today (IMHO), but > what I would like to do, is good looping, which would be important for > games, which would like to loop a background song seamlessly. It could also > be that somebody wants to play along with a drum track (and the drum track > is in the MIDI file), and so he adds the midi file 100 times. (Also > player.reset-synth must be set to "no") > > So to give you an overview - with the 1.1.2 architecture, while it improves > some use cases, it doesn't do much to help out midi players. > The 1.1.2 architecture splits FS into two parts - one hard real-time safe > part, which contains the rendering. So when you (or the audio drivers) call > fluid_synth_write_s16/float, it should be guaranteed a quick return. This is > to avoid underruns and the clicks that comes from it. This part is now in > the rvoice directory. > > To complicate matters, there are some MIDI synth events which we cannot do > in a hard real-time safe way. So the MIDI engine - that transforms MIDI > events into individual voices - is not real-time safe, and calls into that > API are synchronized. Once the MIDI engine has completed the processing of a > MIDI event, it stores commands to the rvoice engine in a queue. > > Also important in this context is the system timer vs the sample timer. If > we use the system timer, the problem with real-time safety is solved, > because we have an additional thread checking the computer's system timer, > calling into the API at predefined times. This however leads to another > problem instead, which we called the "drunk drummer" problem a year or two > ago. That is, we can't intercept a fluid_synth_write_s16 call in the middle > to insert a MIDI event, so all MIDI events become quantizised to the buffer > size, causing bad timing. > > So therefore the sample timer was invented, which enables callbacks from > the middle of the rendering, which could in turn can call the MIDI player or > sequencer to insert MIDI events appropriately. This is good for timing and > reliability, and a must for faster-than-realtime-rendering, but bad for > real-time/underrun safety. > > So the situation is not optimal either way (and has never been). I've had > loose thoughts about how to attack this problem, but not thought them > through enough to start discussin
Re: [fluid-dev] Making MIDI player read from a buffer
On 19/10/2010, at 6:07 PM, David Henningsson wrote: On 2010-10-19 00:02, Pedro Lopez-Cabanillas wrote: On Monday 18 October 2010, Matt Giuca wrote: So my questions for any interested observers (especially FluidSynth developers): 1. Is this feature worth implementing at all? If you are motivated to do this work, then go ahead. Nobody has any right to stop you of adding an improvement that you want to implement, and you believe that it is valuable. ...as long as it doesn't break anything else, which is the hard part. I don't want to comment about the implementation details in your proposal, either. If you feel that the current API needs incompatible changes, then this feature should go in a library version 2. That's all. Not a big deal, this is going to happen sooner or later. If you're talking about dropping backwards compatibility, then that is a big deal IMO. We might come to a point where we believe it is necessary, but I don't see it coming right now. It would mean all distros shipping with two FS library versions, then someone finds a bug in the old one, and we only support the new one, and so on... There was a proposal by Antoine Schmitt in this mailing list some time ago about reimplementing the MIDI player using the sequencer API, in a similar way of James' SDL patches. That may work if some problems are solved first: the current MIDI parser is incomplete, and the sequencer lacks some features. If this refactoring is going to happen some day it would be complementary, not redundant, WRT your feature of reading MIDI data from a buffer instead of disk files. Talking about my personal interests, MIDI applications often need to parse MIDI files to manipulate MIDI events (sometimes interactively) before sending the events to the MIDI sequencer engine. For instance, to change the instrument maps of melodic and percussion instruments (MIDI mappers), or to manipulate controller events (i.e. MIDI volume), muting MIDI channels, transposing MIDI notes on melodic channels, synchronous display of SMF embedded song lyrics, and so on. All these functions belong not only to MIDI editors, but also to players like KMid (http:// kmid2.sourceforge.net). This program has backends using the OS native sequencer services for Linux, Windows and MacOSX, and I would like to implement a pure FluidSynth backend. To do that, FluidSynth needs some new features for manipulating the playlists, but more important: a new mechanism in the MIDI player to route selected events to the client application, that may change them before playing. Opinions are welcome. I think inserting a hook would be quite easy. fluid_synth_handle_midi_event is called from fluid_track_send_events, and it seems like that would be a good place to insert the hook - let the fluid_track_send_events call a user-specified callback, then let the user-specified callback call fluid_synth_handle_midi_event, or call some other fluid_synth_* function, or write to the console, or eat porridge [1], etc. // David [1] This proposal was added by my unconscious, subtly trying to make me go and have breakfast soon. ;-) ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev Would there be value in looking at the patch than Jim Henry mentioned (given that it has been effectively tested for many years by hundreds of users of Miditzer) to see whether it is compatible with the current code. With any luck it may have fluid_synth_handle_porridge_event already implemented ;-) Graham ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
On 2010-10-19 00:02, Pedro Lopez-Cabanillas wrote: On Monday 18 October 2010, Matt Giuca wrote: So my questions for any interested observers (especially FluidSynth developers): 1. Is this feature worth implementing at all? If you are motivated to do this work, then go ahead. Nobody has any right to stop you of adding an improvement that you want to implement, and you believe that it is valuable. ...as long as it doesn't break anything else, which is the hard part. I don't want to comment about the implementation details in your proposal, either. If you feel that the current API needs incompatible changes, then this feature should go in a library version 2. That's all. Not a big deal, this is going to happen sooner or later. If you're talking about dropping backwards compatibility, then that is a big deal IMO. We might come to a point where we believe it is necessary, but I don't see it coming right now. It would mean all distros shipping with two FS library versions, then someone finds a bug in the old one, and we only support the new one, and so on... There was a proposal by Antoine Schmitt in this mailing list some time ago about reimplementing the MIDI player using the sequencer API, in a similar way of James' SDL patches. That may work if some problems are solved first: the current MIDI parser is incomplete, and the sequencer lacks some features. If this refactoring is going to happen some day it would be complementary, not redundant, WRT your feature of reading MIDI data from a buffer instead of disk files. Talking about my personal interests, MIDI applications often need to parse MIDI files to manipulate MIDI events (sometimes interactively) before sending the events to the MIDI sequencer engine. For instance, to change the instrument maps of melodic and percussion instruments (MIDI mappers), or to manipulate controller events (i.e. MIDI volume), muting MIDI channels, transposing MIDI notes on melodic channels, synchronous display of SMF embedded song lyrics, and so on. All these functions belong not only to MIDI editors, but also to players like KMid (http://kmid2.sourceforge.net). This program has backends using the OS native sequencer services for Linux, Windows and MacOSX, and I would like to implement a pure FluidSynth backend. To do that, FluidSynth needs some new features for manipulating the playlists, but more important: a new mechanism in the MIDI player to route selected events to the client application, that may change them before playing. Opinions are welcome. I think inserting a hook would be quite easy. fluid_synth_handle_midi_event is called from fluid_track_send_events, and it seems like that would be a good place to insert the hook - let the fluid_track_send_events call a user-specified callback, then let the user-specified callback call fluid_synth_handle_midi_event, or call some other fluid_synth_* function, or write to the console, or eat porridge [1], etc. // David [1] This proposal was added by my unconscious, subtly trying to make me go and have breakfast soon. ;-) ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
On 2010-10-19 02:07, Matt Giuca wrote: Hi David, James, Pedro, Thanks for a quick discussion. David Henningson wrote: ...although this would only be in fluid_midi.c, right? It wouldn't affect other files. Correct. I'd personally prefer the client handling memory entirely. This has two advantages: * We won't have to do "free" in a context that might be real-time sensitive. * The client does not have to use the same memory allocator as fluidsynth. OK, I thought about this when I was typing my first email, but I realised there would be a major drawback in that without a garbage collector, the client would need to somehow know when it is safe to free the memory. As far as I can tell, you can really only be sure the fluid_player is finished with it if the entire playlist has ended, or you have manually stopped or deleted the fluid_player. Therefore if you were creating a playlist from some file-like objects, you would need to load them all into memory, store pointers to each of them somewhere, wait for the fluid_player to end, then free them all. We could also copy the memory. While copying memory around is inoptimal, that might be a secondary concern. At least that would give us the most future flexibility. It seems in almost all cases I can think of, the client is going to want to allocate a buffer specially for FluidSynth to read, populate it from whatever file-like object it has in mind, and then pass it to FluidSynth, never to read the buffer (in the client) again. There would be a lot of overhead if all the clients had to do manual garbage collection on the buffers. As for the client having to use the same memory allocator, true, but as I said most clients will simply quickly allocate a buffer which is immediately passed to Fluid and forgotten about, so even if the client is using another allocator, it could just use malloc at this one part. For example, a C++ program would typically use new[] to construct arrays, but it would use malloc to allocate this particular buffer to pass to FluidSynth. (Though I agree it's not too nice for a library to free a data structure allocated by the client.) If so, we should probably also add fluid_malloc / fluid_realloc / fluid_free as API additions to make sure the same memory allocator is used. After all, in a future version of FS, we might want to switch memory allocator, write our own for some reason, etc. I don't know much about real-time programming. But I imagine that if you are loading MIDI files into memory each time you hit a new playlist entry, you have lost your real-time-ness anyway (at least, in between songs), since you will be allocating a new internal data structure, reading a file from disk, and freeing the previous one. Does adding this free make matters any worse for real-time applications? Not really, but this is more about not making API additions that will make it hard or impossible to make the MIDI player real-time safe in the future. One hard part of FluidSynth is that it has so many use cases, and we can't fail a single one of them. What we can't do good enough today (IMHO), but what I would like to do, is good looping, which would be important for games, which would like to loop a background song seamlessly. It could also be that somebody wants to play along with a drum track (and the drum track is in the MIDI file), and so he adds the midi file 100 times. (Also player.reset-synth must be set to "no") So to give you an overview - with the 1.1.2 architecture, while it improves some use cases, it doesn't do much to help out midi players. The 1.1.2 architecture splits FS into two parts - one hard real-time safe part, which contains the rendering. So when you (or the audio drivers) call fluid_synth_write_s16/float, it should be guaranteed a quick return. This is to avoid underruns and the clicks that comes from it. This part is now in the rvoice directory. To complicate matters, there are some MIDI synth events which we cannot do in a hard real-time safe way. So the MIDI engine - that transforms MIDI events into individual voices - is not real-time safe, and calls into that API are synchronized. Once the MIDI engine has completed the processing of a MIDI event, it stores commands to the rvoice engine in a queue. Also important in this context is the system timer vs the sample timer. If we use the system timer, the problem with real-time safety is solved, because we have an additional thread checking the computer's system timer, calling into the API at predefined times. This however leads to another problem instead, which we called the "drunk drummer" problem a year or two ago. That is, we can't intercept a fluid_synth_write_s16 call in the middle to insert a MIDI event, so all MIDI events become quantizised to the buffer size, causing bad timing. So therefore the sample timer was invented, which enables callbacks from the middle of the rendering, which could in turn can call th
Re: [fluid-dev] Making MIDI player read from a buffer
Pedro, It sounds like you are suggesting a feature that the Miditzer virtual organ uses. A number of years ago Sebastian Frippiat suggested extending FluidSynth so that the MIDI Player would pass the MIDI events to the caller rather than playing them. At the time there was no interest in his proposal. I think this was in part because he wanted just to use FluidSynth as a MIDI file reader and it was felt that was not within the scope of FluidSynth's purpose. He did post patches for doing this. We picked up those patches for the Miditzer and they are in the version of FluidSynth used with the Miditzer. As Pedro suggests, the Miditzer takes MIDI input, including the input from the FluidSynth MIDI file reader, and vigorously manipulates the MIDI data before sending it to FluidSynth to be realized in order to create the organ performance paradigm which just doesn't fit within the standard MIDI specification. (By that I mean there is no way to fully encode the performance of an organ according to the MIDI specification.) If there is now interest in extending the FluidSynth MIDI file player to send the MIDI messages to the caller for processing rather than playing them, I certainly support such an effort. Jim Henry On 10/18/2010 3:02 PM, Pedro Lopez-Cabanillas wrote: Talking about my personal interests, MIDI applications often need to parse MIDI files to manipulate MIDI events (sometimes interactively) before sending the events to the MIDI sequencer engine. For instance, to change the instrument maps of melodic and percussion instruments (MIDI mappers), or to manipulate controller events (i.e. MIDI volume), muting MIDI channels, transposing MIDI notes on melodic channels, synchronous display of SMF embedded song lyrics, and so on. All these functions belong not only to MIDI editors, but also to players like KMid (http://kmid2.sourceforge.net). This program has backends using the OS native sequencer services for Linux, Windows and MacOSX, and I would like to implement a pure FluidSynth backend. To do that, FluidSynth needs some new features for manipulating the playlists, but more important: a new mechanism in the MIDI player to route selected events to the client application, that may change them before playing. Opinions are welcome. Regards, Pedro ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
Hi David, James, Pedro, Thanks for a quick discussion. David Henningson wrote: > ...although this would only be in fluid_midi.c, right? It wouldn't affect > other files. Correct. > I'd personally prefer the client handling memory entirely. This has two > advantages: > * We won't have to do "free" in a context that might be real-time sensitive. > * The client does not have to use the same memory allocator as fluidsynth. OK, I thought about this when I was typing my first email, but I realised there would be a major drawback in that without a garbage collector, the client would need to somehow know when it is safe to free the memory. As far as I can tell, you can really only be sure the fluid_player is finished with it if the entire playlist has ended, or you have manually stopped or deleted the fluid_player. Therefore if you were creating a playlist from some file-like objects, you would need to load them all into memory, store pointers to each of them somewhere, wait for the fluid_player to end, then free them all. It seems in almost all cases I can think of, the client is going to want to allocate a buffer specially for FluidSynth to read, populate it from whatever file-like object it has in mind, and then pass it to FluidSynth, never to read the buffer (in the client) again. There would be a lot of overhead if all the clients had to do manual garbage collection on the buffers. As for the client having to use the same memory allocator, true, but as I said most clients will simply quickly allocate a buffer which is immediately passed to Fluid and forgotten about, so even if the client is using another allocator, it could just use malloc at this one part. For example, a C++ program would typically use new[] to construct arrays, but it would use malloc to allocate this particular buffer to pass to FluidSynth. (Though I agree it's not too nice for a library to free a data structure allocated by the client.) I don't know much about real-time programming. But I imagine that if you are loading MIDI files into memory each time you hit a new playlist entry, you have lost your real-time-ness anyway (at least, in between songs), since you will be allocating a new internal data structure, reading a file from disk, and freeing the previous one. Does adding this free make matters any worse for real-time applications? A possible work-around for this is having fluid_player_add_mem take an extra argument of type void(*)(void*) (a function pointer which accepts a void* and returns void), which is called on the buffer when the player is done with it. This lets you specify your own de-allocation function (for example, C++ clients could pass a function which calls delete[] on a new[]-allocated array), or pass a function which does nothing, allowing clients to ignore the signal and perform their own memory-management. But the majority of clients could just pass 'free' as an argument, which means FluidSynth would simply free the memory with no further work on the part of the client. Or maybe that's going too far. > > In addition, here are things that might or might not be real-time sensitive. > This conversion sounds like time intensive. OK, again I don't know much about real-time programming, so I might have to get someone to check my code afterwards to let me know if I've "broken" some real-time-ness of FluidSynth. > Here's a compromise: > > struct loadable_file > { > char* filename; > void* data; > size_t data_length; > } > > (You don't need an enum because either one will be NULL.) > > But then, at file load time, if filename != NULL, load the file into the data > and data_length fields, then do midi parsing, followed by freeing the data > buffer again. Then we at least have only one midi file in memory at a time. OK that does seem like a good solution. Note however that before when you said "That is probably a good thing though," (referring to the fact that you get errors upon calling fluid_player_add rather than at load time), that is no longer the case -- with this design you would get file access errors as each file comes up in the playlist. > The other end of it would be to run through all of the midi conversion > functions inside fluid_player_add_mem. With all time intensive tasks done, we > might be able to switch from one midi file to another very quickly (without > risking underruns). That'd be nice, but I don't know about the memory > consumption. You mean fully parse the MIDI file into track data in fluid_player_add_mem. I see, well I don't think I'll tackle that just yet, but I agree it could be an interesting trade-off (somewhat increased memory consumption, but having no overhead -- disk or memory -- in switching MIDI files). Well, garbage collection issues notwithstanding, I think I'll start implementing the "compromise" method you describe. I will share the code once I have something, Matt ___ fluid-dev mailing lis
Re: [fluid-dev] Making MIDI player read from a buffer
On Monday 18 October 2010, Matt Giuca wrote: > So my questions for any interested observers (especially FluidSynth developers): > > 1. Is this feature worth implementing at all? If you are motivated to do this work, then go ahead. Nobody has any right to stop you of adding an improvement that you want to implement, and you believe that it is valuable. I don't want to comment about the implementation details in your proposal, either. If you feel that the current API needs incompatible changes, then this feature should go in a library version 2. That's all. Not a big deal, this is going to happen sooner or later. There was a proposal by Antoine Schmitt in this mailing list some time ago about reimplementing the MIDI player using the sequencer API, in a similar way of James' SDL patches. That may work if some problems are solved first: the current MIDI parser is incomplete, and the sequencer lacks some features. If this refactoring is going to happen some day it would be complementary, not redundant, WRT your feature of reading MIDI data from a buffer instead of disk files. Talking about my personal interests, MIDI applications often need to parse MIDI files to manipulate MIDI events (sometimes interactively) before sending the events to the MIDI sequencer engine. For instance, to change the instrument maps of melodic and percussion instruments (MIDI mappers), or to manipulate controller events (i.e. MIDI volume), muting MIDI channels, transposing MIDI notes on melodic channels, synchronous display of SMF embedded song lyrics, and so on. All these functions belong not only to MIDI editors, but also to players like KMid (http://kmid2.sourceforge.net). This program has backends using the OS native sequencer services for Linux, Windows and MacOSX, and I would like to implement a pure FluidSynth backend. To do that, FluidSynth needs some new features for manipulating the playlists, but more important: a new mechanism in the MIDI player to route selected events to the client application, that may change them before playing. Opinions are welcome. Regards, Pedro ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
On Mon, 18 Oct 2010 16:53:07 +0200 David Henningsson wrote: > struct loadable_file > { > char* filename; > void* data; > size_t data_length; > } > > (You don't need an enum because either one will be NULL.) > > But then, at file load time, if filename != NULL, load the file into > the data and data_length fields, then do midi parsing, followed by > freeing the data buffer again. Then we at least have only one midi > file in memory at a time. Without getting too far into the details of it, this is the solution I vaguely had in mind because it's relatively simple. James ___ fluid-dev mailing list fluid-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/fluid-dev
Re: [fluid-dev] Making MIDI player read from a buffer
On 2010-10-18 16:14, Matt Giuca wrote: There was a discussion in the thread "FluidSynth backend for SDL_mixer" about the difficulty with the current implementation of the FluidSynth API's MIDI file player, in that it will only load a MIDI file via a filename (fluid_player_add -- http://fluidsynth.sourceforge.net/api/midi_8h.html#a1ac5b59e4ab9d0f48e917dda0a9a4403 -- seems to be the only way to load anything into the MIDI player). This means if you need to load a MIDI file from any source that is not a regular disk file (e.g., from an already-open FILE* such as stdin, a network socket, an SDL RWop, or another high-level "file-like object" which is not an ordinary file on disk), you are presently out of luck. This apparently was so bad that James Le Cuirot, working on SDL_mixer backend for FluidSynth, wrote a whole MIDI parser ... In that thread, I volunteered to help fix FluidSynth around this (thanks to James for reminding me this morning). It looks like quite a job since the "loading of files via a filename" aspect goes quite deep into the internals of FluidSynth. I thought I'd start this thread to a) see if there is interest in this change, and b) have a discussion about whether I'm going about it right. I think it would be quite useful to fix. What I proposed was not the most general solution to this problem (the "ideal" solution would be to allow any "file-like object" to be plugged into FluidSynth and have it request bytes from that), but a good compromise: Allow FluidSynth to read MIDI file data from a void* memory buffer. Since MIDI files are small, any other "file-like object" could simply load all of the bytes into memory and then pass the void* buffer in. Like I said, it's not ideal, but at least it allows these solutions to function. Thanks for the analysis and willingness to help out with FluidSynth! I can hopefully do this without breaking the existing FluidSynth API, but it would require a lot of changes to the internals. Here we go. ...although this would only be in fluid_midi.c, right? It wouldn't affect other files. 1. INTERFACE CHANGES There is simply one new function, declared in include/fluidsynth/midi.h and defined in src/midi/fluid_midi.c: /** * Add a MIDI file to a player queue, from a buffer in memory. * @param player MIDI player instance * @param buffer Pointer to memory containing the bytes of a complete MIDI * file. The pointer is "stolen" and will be freed by FluidSynth once it is * no longer needed. I'd personally prefer the client handling memory entirely. This has two advantages: * We won't have to do "free" in a context that might be real-time sensitive. * The client does not have to use the same memory allocator as fluidsynth. * @param len Length of the buffer, in bytes. * @return #FLUID_OK */ FLUIDSYNTH_API int fluid_player_add_mem(fluid_player_t* player, void *buffer, size_t len); The idea is that it is possible to add filenames (using fluid_player_add) and memory buffers (using fluid_player_add_mem) interleaved in the queue, so each queue item can either be a filename entry or a memory buffer entry. That's consistent with my thoughts. 2. INTERNAL CHANGES Internally, this will be difficult, as the following data structures are currently hard-wired to deal with filenames/FILE*s (from src/midi/fluid_midi.h): /* * fluid_player */ struct _fluid_player_t { ... fluid_list_t* playlist; /* List of file names */ fluid_list_t* currentfile; /* points to an item in files, or NULL if not playing */ ... } /* * fluid_midi_file */ typedef struct { fluid_file fp; ... } fluid_midi_file; (where fluid_file is a typedef for FILE*). First, fluid_player_add adds the filename to fluid_player::playlist (without loading from disk). This stores the filename as a char* in playlist->data. So playlist->data has to point to a struct instead of a char*. Then, when it gets up to that particular playlist item, it calls fluid_player_load (fluid_midi.c) with that filename, which opens the file into a FILE*. This then temporarily creates a fluid_midi_file object, storing the FILE*, and then calls a bunch of other files to read the bytes of the MIDI file from disk and assemble them into an in-memory data structure inside the fluid_player_t. It then deletes the fluid_midi_file object, and from that point onwards, everything is in memory (our job is done). All of the above architecture would have to be modified to handle reading from a memory buffer. In addition, here are things that might or might not be real-time sensitive. This conversion sounds like time intensive. (Note: Short of using mmap and doing file descriptor tricks, which I'm sure would be Linux-specific or something, there's not really any way to make use of the FILE* infrastructure.) Possibly the easiest way to handle this would be to *completely replace* the existing FILE* stuff with a void* instead, and replace such functions as fluid_midi_file_getc wi
[fluid-dev] Making MIDI player read from a buffer
There was a discussion in the thread "FluidSynth backend for SDL_mixer" about the difficulty with the current implementation of the FluidSynth API's MIDI file player, in that it will only load a MIDI file via a filename (fluid_player_add -- http://fluidsynth.sourceforge.net/api/midi_8h.html#a1ac5b59e4ab9d0f48e917dda0a9a4403 -- seems to be the only way to load anything into the MIDI player). This means if you need to load a MIDI file from any source that is not a regular disk file (e.g., from an already-open FILE* such as stdin, a network socket, an SDL RWop, or another high-level "file-like object" which is not an ordinary file on disk), you are presently out of luck. This apparently was so bad that James Le Cuirot, working on SDL_mixer backend for FluidSynth, wrote a whole MIDI parser ... In that thread, I volunteered to help fix FluidSynth around this (thanks to James for reminding me this morning). It looks like quite a job since the "loading of files via a filename" aspect goes quite deep into the internals of FluidSynth. I thought I'd start this thread to a) see if there is interest in this change, and b) have a discussion about whether I'm going about it right. I think it would be quite useful to fix. What I proposed was not the most general solution to this problem (the "ideal" solution would be to allow any "file-like object" to be plugged into FluidSynth and have it request bytes from that), but a good compromise: Allow FluidSynth to read MIDI file data from a void* memory buffer. Since MIDI files are small, any other "file-like object" could simply load all of the bytes into memory and then pass the void* buffer in. Like I said, it's not ideal, but at least it allows these solutions to function. I can hopefully do this without breaking the existing FluidSynth API, but it would require a lot of changes to the internals. Here we go. 1. INTERFACE CHANGES There is simply one new function, declared in include/fluidsynth/midi.h and defined in src/midi/fluid_midi.c: /** * Add a MIDI file to a player queue, from a buffer in memory. * @param player MIDI player instance * @param buffer Pointer to memory containing the bytes of a complete MIDI * file. The pointer is "stolen" and will be freed by FluidSynth once it is * no longer needed. * @param len Length of the buffer, in bytes. * @return #FLUID_OK */ FLUIDSYNTH_API int fluid_player_add_mem(fluid_player_t* player, void *buffer, size_t len); The idea is that it is possible to add filenames (using fluid_player_add) and memory buffers (using fluid_player_add_mem) interleaved in the queue, so each queue item can either be a filename entry or a memory buffer entry. 2. INTERNAL CHANGES Internally, this will be difficult, as the following data structures are currently hard-wired to deal with filenames/FILE*s (from src/midi/fluid_midi.h): /* * fluid_player */ struct _fluid_player_t { ... fluid_list_t* playlist; /* List of file names */ fluid_list_t* currentfile; /* points to an item in files, or NULL if not playing */ ... } /* * fluid_midi_file */ typedef struct { fluid_file fp; ... } fluid_midi_file; (where fluid_file is a typedef for FILE*). First, fluid_player_add adds the filename to fluid_player::playlist (without loading from disk). This stores the filename as a char* in playlist->data. Then, when it gets up to that particular playlist item, it calls fluid_player_load (fluid_midi.c) with that filename, which opens the file into a FILE*. This then temporarily creates a fluid_midi_file object, storing the FILE*, and then calls a bunch of other files to read the bytes of the MIDI file from disk and assemble them into an in-memory data structure inside the fluid_player_t. It then deletes the fluid_midi_file object, and from that point onwards, everything is in memory (our job is done). All of the above architecture would have to be modified to handle reading from a memory buffer. (Note: Short of using mmap and doing file descriptor tricks, which I'm sure would be Linux-specific or something, there's not really any way to make use of the FILE* infrastructure.) Possibly the easiest way to handle this would be to *completely replace* the existing FILE* stuff with a void* instead, and replace such functions as fluid_midi_file_getc with new implementations which read bytes from the buffer. That would be relatively straightforward. Then fluid_player_add_mem would work naturally with the new infrastructure. The old fluid_player_add function would then wrap around that -- it would load the file from disk into a buffer in memory, then pass that buffer to fluid_player_add_mem. However, I expect this will not be what people want to do, because it fundamentally changes the way fluid_player_add works -- it would load the entire file into memory up-front, rather than the current approach which reads in a few bytes at a time, never loading the whole file into memory. Maybe this is an acceptable trade-off though (since come on, MIDI fi