Sf2Player: added panning and volume envelope support

Finally there's proper support for panning and volume envelopes. This
is achieved by changing parameters of individual voices (one voice is
being created for each note). The new code also replaces the old
panning hacks which played notes on different channels and changed
panning of individual channels.

Closes #2010818.
This commit is contained in:
Tobias Doerffel
2009-08-05 12:30:42 +02:00
parent 4cdcd1a670
commit 4baf459da2
2 changed files with 57 additions and 30 deletions

View File

@@ -47,8 +47,6 @@
#include "embed.cpp"
#define SF2_PANNING_SUPPORT
static const char * __supportedExts[] =
{ "sf2", NULL };
@@ -75,8 +73,9 @@ plugin::descriptor sf2player_plugin_descriptor =
struct SF2PluginData
{
int midiNote;
int midiChannel;
int lastPanning;
float lastVelocity;
fluid_voice_t * fluidVoice;
} ;
@@ -119,10 +118,7 @@ sf2Instrument::sf2Instrument( instrumentTrack * _instrument_track ) :
{
for( int i = 0; i < 128; ++i )
{
for( int j = 0; j < MaxFluidChannels; ++j )
{
m_notesRunning[i][j] = 0;
}
m_notesRunning[i] = 0;
}
m_settings = new_fluid_settings();
@@ -592,47 +588,82 @@ void sf2Instrument::playNote( notePlayHandle * _n, sampleFrame * )
{
SF2PluginData * pluginData = new SF2PluginData;
pluginData->midiNote = midiNote;
pluginData->midiChannel = m_channel;
pluginData->lastPanning = -1;
pluginData->lastVelocity = 127;
pluginData->fluidVoice = NULL;
_n->m_pluginData = pluginData;
m_synthMutex.lock();
#ifdef SF2_PANNING_SUPPORT
updatePatch();
#endif
// get list of current voice IDs so we can easily spot the new
// voice after the fluid_synth_noteon() call
const int poly = fluid_synth_get_polyphony( m_synth );
fluid_voice_t * voices[poly];
unsigned int id[poly];
fluid_synth_get_voicelist( m_synth, voices, poly, -1 );
for( int i = 0; i < poly; ++i )
{
id[i] = 0;
}
for( int i = 0; i < poly && voices[i]; ++i )
{
id[i] = fluid_voice_get_id( voices[i] );
}
fluid_synth_noteon( m_synth, pluginData->midiChannel, midiNote,
fluid_synth_noteon( m_synth, m_channel, midiNote,
_n->getMidiVelocity() );
#ifdef SF2_PANNING_SUPPORT
if( ++m_channel > MaxFluidChannels )
// get new voice and save it
fluid_synth_get_voicelist( m_synth, voices, poly, -1 );
int last = -1;
for( int i = 0; i < poly && voices[i]; ++i )
{
m_channel = 1;
last = i;
const unsigned int newID = fluid_voice_get_id( voices[i] );
if( id[i] != newID || newID == 0 )
{
pluginData->fluidVoice = voices[i];
break;
}
}
if( pluginData->fluidVoice == NULL )
{
pluginData->fluidVoice = voices[last];
}
#endif
m_synthMutex.unlock();
m_notesRunningMutex.lock();
++m_notesRunning[midiNote][pluginData->midiChannel-1];
++m_notesRunning[midiNote];
m_notesRunningMutex.unlock();
}
#ifdef SF2_PANNING_SUPPORT
SF2PluginData * pluginData = static_cast<SF2PluginData *>(
_n->m_pluginData );
if( pluginData->lastPanning != _n->getPanning() )
{
int pan = 0 +
const float pan = -500 +
( (float)( _n->getPanning() - PanningLeft ) ) /
( (float)( PanningRight - PanningLeft ) ) *
( (float)( 127 - 0 ) );
fluid_synth_cc( m_synth, pluginData->midiChannel, 0x0A, pan );
( (float)( PanningRight - PanningLeft ) ) * 1000;
fluid_voice_gen_set( pluginData->fluidVoice, GEN_PAN, pan );
fluid_voice_update_param( pluginData->fluidVoice, GEN_PAN );
pluginData->lastPanning = _n->getPanning();
}
#endif
const float currentVelocity = _n->volumeLevel( tfp ) * 127;
if( pluginData->lastVelocity != currentVelocity )
{
fluid_voice_gen_set( pluginData->fluidVoice, GEN_VELOCITY,
currentVelocity );
fluid_voice_update_param( pluginData->fluidVoice, GEN_VELOCITY );
// make sure, FluidSynth modulates our changed GEN_VELOCITY via internal
// attenuation modulator, so changes take effect (7=Volume CC)
fluid_synth_cc( m_synth, m_channel, 7, 127 );
pluginData->lastVelocity = currentVelocity;
}
}
@@ -704,15 +735,13 @@ void sf2Instrument::deleteNotePluginData( notePlayHandle * _n )
SF2PluginData * pluginData = static_cast<SF2PluginData *>(
_n->m_pluginData );
m_notesRunningMutex.lock();
const int n = --m_notesRunning[pluginData->midiNote]
[pluginData->midiChannel-1];
const int n = --m_notesRunning[pluginData->midiNote];
m_notesRunningMutex.unlock();
if( n <= 0 )
{
m_synthMutex.lock();
fluid_synth_noteoff( m_synth, pluginData->midiChannel,
pluginData->midiNote );
fluid_synth_noteoff( m_synth, m_channel, pluginData->midiNote );
m_synthMutex.unlock();
}

View File

@@ -46,8 +46,6 @@ class notePlayHandle;
class patchesDialog;
class QLabel;
const int MaxFluidChannels = 5;
class sf2Instrument : public instrument
{
@@ -129,7 +127,7 @@ private:
QMutex m_synthMutex;
QMutex m_loadMutex;
int m_notesRunning[128][MaxFluidChannels];
int m_notesRunning[128];
sample_rate_t m_internalSampleRate;
int m_lastMidiPitch;
int m_channel;