|
From: | Zachary Northrup |
Subject: | [fluid-dev] Non-Real-Time Rendering |
Date: | Thu, 26 Apr 2007 17:51:34 -0400 |
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.
|
[Prev in Thread] | Current Thread | [Next in Thread] |