Re: [fluid-dev] Making MIDI player read from a buffer

2011-02-20 Thread Matt Giuca
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

2011-02-20 Thread David Henningsson

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

2011-02-19 Thread Matt Giuca
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

2011-01-25 Thread Matt Giuca
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

2010-12-05 Thread Matt Giuca
> 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

2010-12-04 Thread James Le Cuirot
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

2010-12-03 Thread Matt Giuca
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

2010-10-20 Thread Matt Giuca
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

2010-10-19 Thread Jim Henry

 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

2010-10-19 Thread Matt Giuca
>
>  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

2010-10-19 Thread Pedro Lopez-Cabanillas
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

2010-10-19 Thread Pedro Lopez-Cabanillas
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

2010-10-19 Thread Pedro Lopez-Cabanillas
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

2010-10-19 Thread David Henningsson

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

2010-10-19 Thread David Henningsson

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

2010-10-19 Thread Matt Giuca
>
> 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

2010-10-19 Thread Graham Wykes


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

2010-10-19 Thread David Henningsson

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

2010-10-18 Thread David Henningsson

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

2010-10-18 Thread Jim Henry

 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

2010-10-18 Thread Matt Giuca
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

2010-10-18 Thread Pedro Lopez-Cabanillas
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

2010-10-18 Thread James Le Cuirot
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

2010-10-18 Thread David Henningsson

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

2010-10-18 Thread Matt Giuca
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