I just noticed that on the "Future of Fluidsynth" page, it lists non-real-time 
rendering as feature. Um, I am currently using Fluidsynth for this very task in 
my program, Z-Maestro (you can find it on the FluidSynth applications page). 
Has this never been done before, or am I misreading it? I can render a complete 
30 second project in roughly 2-5 seconds give or take depending on sample rate, 
complexity of the song, and a few other things.

Since I'm doing it all in managed VB.NET, the code sample will probably be 
almost useless, but I'll explain what I do as well. First, I take the music 
project and process it, compiling a list of all MIDI events for every channel. 
I sort the list of MIDI events by position to put them in chronological order. 
Then, I have a function that loops from the beginning of the project to a point 
measured in audio samples. Since the smallest increment of an event position is 
a 16th note, I loop from the first 16th note to the last one inside the audio 
sample range. For each 16th note, I send any events that exist at that position 
and then I call fluid_synth_write_s16 (which is called FillBuffer in my 
program) sending in the length, in audio samples, of a 16th note for the length 
of the buffer. Finally, I simply append the result to my main buffer.

The final code in my program looks like this:

        Protected Function RenderMIDI(ByVal length As Integer) As Short()
            Dim instBuff As New ArrayList
            Dim hasSampled As Boolean = False
            Dim lastSamplePos As Integer
            For i As Integer = _currentSamplePos To (_currentSamplePos + length 
- 1)
                If (i / _samplesPerMeasure) Mod (1 / 16) = 0 Then
                    If hasSampled Then
                        instBuff.AddRange(inst.Synthesizer.FillBuffer((1 / 16) 
* _samplesPerMeasure))
                        SendEventsAtPos(i / _samplesPerMeasure)
                    Else
                        instBuff.AddRange(inst.Synthesizer.FillBuffer(i - 
_currentSamplePos))
                        SendEventsAtPos(i / _samplesPerMeasure)
                    End If
                    hasSampled = True
                    lastSamplePos = i
                End If
            Next
            instBuff.AddRange(inst.Synthesizer.FillBuffer(_currentSamplePos + 
length - lastSamplePos))
            Dim instBuffArr(instBuff.Count - 1) As Short
            instBuff.CopyTo(instBuffArr)
            Return instBuffArr
        End Function

"inst.Synthesizer" is a managed wrapper class for a FluidSynth synthesizer. 
"_currentSamplePos" is the starting sample to use. "_samplesPerMeasure" is a 
precalculated value containing literally the number of audio samples per 
measure based on the temp, sample rate, etc. The "AddRange" function simply 
appends an array to the "ArrayList". The "SendEventsAtPos" method simply sends 
any MIDI events existing at the specified position to the synthesizer.

Once again, if this is new, please tell me (and feel free to ask about the 
algorithm). By the way, I'm using version 1.0.0 of FluidSynth due to some 
upgrading issues, if that makes any difference.
_______________________________________________
fluid-dev mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/fluid-dev

Reply via email to