Hi Ben,
Thanks a lot for your contribution you have done a good job.
After looking the result of the compiler you have posted on your site, I
have found
some differences that strike me.
You will find below an new attached file: fluid_synth_mono.c.
Please may you:
1) substitute the one you have: in /src/synth/fluid_synth_mono.c by
the attached new one.
2) rebuild.
3) And tell if the issue is always there ?.
Thanks you very much
jjc
Le 06/07/2016 14:37, Ben Gonzales a écrit :
Hi all.
When I said "are there any tests...?" I didn't expect so many!
Nevertheless, I have completed the tests, and I have put all the
resulting files in:
http://gonzos.net/fluid-dev
Also in that directory are the soundfont, and other files I have
referenced in this discussion.
cmakelog.txt is the results of the command <cmake ..> from the empty
build directory
makelog.txt is the results of the command <make> from the build directory
I think I covered all the variations that you requested. They are
summarised in polymonotests.pdf
ewi.conf is the configuration file I use to start fluidsynth, and the
command line in the batch file is
nice -20 fluidsynth --server --no-shell --audio-driver=alsa \
-o audio.alsa.device=hw:$CARDNO \
--load-config=$CONFIG --portname="$SYNTHPORT" &>
/home/pi/ewi/scripts/fluidsynth.out &
Notes:
- The %CPU is taken from the <top> command, and represents what is
used by FluidSynth only. I arriving at the readings, I had to do a bit
of "averaging" in my head, as the % utilisation fluctuated. I was not
running the Xwindows graphical interface - it was all done via ssh.
- each test was done with a fresh instance of fluidsynth
- the ewi.conf file is a "snapshot" of one of its possible states - it
gets changed depending on what options are selected.
- I tested all the presets in the soundfont. The tenor sax displays
the worst effects on the CPU, the clarinet displays the least.
- The test with 24 notes was the test I did to see how far I could go
before getting audio distortion as a result of high CPU load
Ben
On 06/07/16 19:17, jean-jacques.ceresa wrote:
Hi Ben,
>Is there any test I could run on the Pi....
While i'm preparing my RPi2, could you please:
Describe and localize when you see excess CPU usage. followings the
tests below:
0)Building steps:
0.1) Which options did you choose at cmake time (please send the
summary log or put it to your WebSite) ?.
0.1) Please send the log of compiler or put it on your WebSite ?.
0.2) What are the fluidsynth arguments when you start it ?.
1)Playing steps
1.1) What is the meter you use to see CPU usage (probably the one to
top right of X windows graphic interface) ?
1.1.1) Please note the meter value when issue occurs.
1.2) Using your soundfont (gonzos-20160702.sf2), which preset causes
the issue ?, and which preset doesn't cause the issue ?.
1.3) I remember the issue is when you play (in mono mode) (at the the
noteOn time), but i 'm not sure ?. Please confirm.
1.4) Assuming the issue occurs in mono mode, does this issue occur in
poly mode ? (using the same preset).
1.4.1) Is it when you play staccato (n1On,n1Off,n1On,n1Off,...) on
the same note ?
1.4.2) Is it when you play staccato (n1On,n1Off,n2On,n2Off,...) on
different note ?
1.4.2) Is it when you play legato (n1On,,n2On,n1Off,n3On,n2Off...) ?,
please note the legato mode number (0 to 3).
The following test are related to Element remarks
2) Please do the test 1.x.x with Reverb and Chorus On and when the
issue occurs, do the same tests without Reverb/Chorus.
Thanks a lot.
jjc
Le 06/07/2016 00:28, Ben Gonzales a écrit :
Hi all.
Is there any test I could run on the Pi that would help you analyse
the problem?
Ben
On 06/07/16 04:55, Element Green wrote:
Hello,
I'm not sure if it could be the issue or not. But I remember a
long while back (many years) FluidSynth used to have issues with
denormal numbers causing excessive CPU usage. That would be
floating point numbers which are very small, but not 0. I don't
know if ARM processors deal with denormal numbers in software,
which would result in poor performance and possibly floating point
exception handlers being triggered. It seems like this would more
often occur when the audio went towards silence.
Some general information on this:
https://en.wikipedia.org/wiki/Denormal_number#Performance_issues
Might be worth looking in to. Code was added in certain areas to
detect if a number was below a very small value and if it was, then
it would be forced to 0. Maybe there are still some areas where
this is occurring which are only affecting this particular platform?
Best regards,
Element
On Tue, Jul 5, 2016 at 11:21 AM, jean-jacques.ceresa
<jean-jacques.cer...@enac.fr> wrote:
Hi Ben,
On Windows, using your soundfont (gonzos-20160702.sf2), in mono
mode i haven't expererienced absolutely no cpu excess usage, on
alls 6 presets.
I have look inside the preset. Each preset make use of 2
simulateneous voices maximum. So this is a very low CPU usage
soundfont.
Normally on a RPi2 you can run 180 voices (using the 4 cores of
course). Even if fluidsynth use only one core, the maximum
number of voices
falls to 45 which is sufficient to play any preset on this
soundfont. So really, i don't understand what happens on your
setting.
Anyway, i have got a RPi2. So I will try this and also an other
machine with Debian. I will return the results, using the same
soundfont.
>The legato is working, and I have noticed that if I do a long
descending glissando to the lower register on the clarinet, the
voice that I end up with
> on the low note is the voice I started with - I don't get the
low reedy sound until I stop and play the note again.
Jean-Jacques said this was a limitation.
Yes , i confirm this is currently a know limitation and it
occurs only on legato mode 1,2,3 but not on legato mode 0.
Playing a legato passage, n1,n2,n3,... using legato mode 1,2,3:
The notes (n2,n3,..) following the first (n1) make use of
running voices of n1, (regardless of the keyRange and Velocity
Range), so the notes n2,n3,... make use
of the IZ (Instruments Zone) of note n1 ignoring possible
others IZ with their samples. In others words, the actual patch
doesn't not follows fully the instructions
given by the soundfont designer. This is a serious limitation.
But anyway, i 'm working to cancel this limitation.
jjc
Le 02/07/2016 14:02, Ben Gonzales a écrit :
Hi
I downloaded the git snapshot, used the patch from Mr(?) Horn
(thankyou), and re-complied.
I'm still experiencing the CPU runaway. It happens a) if I put
the channel I'm using into MONO or b) if I use cc ch 68 127
(legato on). It doesn't matter which setlegatomode I am using
for the channel. Note that it happens on 5 out of 6 of the
voices I am using. I can't see any significant config
differences between the voices when using Swami. One voice
works fine.
The legato is working, and I have noticed that if I do a long
descending glissando to the lower register on the clarinet,
the voice that I end up with on the low note is the voice I
started with - I don't get the low reedy sound until I stop
and play the note again. Jean-Jacques said this was a limitation.
For info, I'm running a RPi2 with Raspbian Jessie, all latest
updates installed. I'm trying to get legato working on
channels 10-15 inclusive, and I'm not using the other channels.
Ben
_______________________________________________
fluid-dev mailing list
fluid-dev@nongnu.org
https://lists.nongnu.org/mailman/listinfo/fluid-dev
_______________________________________________
fluid-dev mailing list
fluid-dev@nongnu.org
https://lists.nongnu.org/mailman/listinfo/fluid-dev
_______________________________________________
fluid-dev mailing list
fluid-dev@nongnu.org
https://lists.nongnu.org/mailman/listinfo/fluid-dev
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#include "fluid_synth.h"
#include "fluid_chan.h"
/** monophonic playing *******************************************************/
extern void fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t* synth,
int chan, int key);
/*-----------------------------------------------------------------------------
Monophonic list methods
------------------------------------------------------------------------------*/
/**
* Add a note to the monophonic list.
* @param chan fluid_channel_t
* @param key MIDI note number (0-127)
* @param vel MIDI velocity (0-127, 0=noteoff)
* return prev index.
*/
static short
fluid_channel_add_monolist(fluid_channel_t* chan, unsigned char key,
unsigned char vel)
{
short iPrev = chan->iLast;
short iNext = chan->iNext;
chan->monolist[iNext].note = key;
chan->monolist[iNext].vel = vel;
chan->iLast = iNext; /* most recent adding */
/* iNext will be used for the next adding */
chan->iNext = chan->monolist[iNext].next;
if(chan->nNotes < maxNotes) chan->nNotes++; /* update nNotes */
else { /* overflow situation. So circular motion for iFirst */
chan->iFirst = chan->iNext;
/* warning */
FLUID_LOG(FLUID_INFO, "Overflow on monophonic list channel %d ",
chan->channum);
}
return iPrev;
}
/**
* Search a note in the monophonic list.
* @param chan fluid_channel_t
* @param key MIDI note number (0-127) to search
* @return index of the note if find, -1 otherwise.
*/
static short
fluid_channel_search_monolist(fluid_channel_t* chan, unsigned char key)
{
short n = chan->nNotes; /* number of notes in monophonic list */
short i= chan->iFirst; /* search starts at iFirst included */
while(n) {
if(chan->monolist[i].note == key) break; /* found */
i = chan->monolist[i].next; /* next element */
n--;
}
if (n) return i;/* found i */
else return -1; /* not found */
}
/**
* remove a note from the monophonic list.
* @param chan fluid_channel_t
* @param i, index of the note to remove
* If i is invalid or the list is empty, the function do nothing.
* return prev index (>= 0) if the note is the last note in the list
-1 otherwise.
*/
static short
fluid_channel_rem_monolist(fluid_channel_t* chan, short i)
{
short iPrev = -1;
if(i < 0 || i >= maxNotes || !chan->nNotes) return 0;
/* index is valid */
/* The element is about to be removed and inserted between iLast and
iNext */
/* Note: when i is egal to iLast or egal to iFirst, Removing/Inserting
isn't necessary */
if (i == chan->iLast) { /* Removing/Inserting isn't necessary */
/* update iLast to the previous if it exists */
iPrev = chan->monolist[i].prev;
if(chan->iLast != chan->iFirst) chan->iLast = iPrev;
chan->iNext = i; /* i becames iNext for the next adding */
}
else { /* i is before iLast */
if(i == chan->iFirst) chan->iFirst = chan->monolist[i].next;
else { /* i is between iFist ans iLast */
/* Removing element i and inserting between iLast and
iNext */
unsigned char next,prev;
/* removing by chainning prev and next */
next = chan->monolist[i].next; prev =
chan->monolist[i].prev;
chan->monolist[next].prev = prev;
chan->monolist[prev].next = next;
/* inserting between iLast and iNext */
chan->monolist[i].next = chan->iNext;
chan->monolist[chan->iNext].prev = i;
chan->monolist[i].prev = chan->iLast;
chan->monolist[chan->iLast].next = i;
chan->iNext = i; /* i becames iNext for the next adding
*/
}
}
chan->nNotes--;
return iPrev;
}
/**
* remove all notees from the monophonic list.
* @param chan fluid_channel_t
*/
void fluid_channel_clear_monolist(fluid_channel_t* chan)
{
chan->iFirst = chan->iLast = chan->iNext = chan->nNotes = 0;
}
/**
* The monophonic list is flushed keeping last note only.
* @param chan fluid_channel_t
*/
void fluid_channel_keep_lastnote_monolist(fluid_channel_t* chan)
{
chan->iFirst = chan->iLast;
chan->nNotes = 1;
}
/**
* The function store the note in the first position of monophonic list
* @param chan fluid_channel_t
*/
void fluid_channel_set_onenote_monolist(fluid_channel_t* chan, unsigned char
key,
unsigned char vel)
{
fluid_channel_clear_monolist(chan);
fluid_channel_add_monolist(chan, key, vel);
}
/*-----------------------------------------------------------------------------
noteon - noteoff on a channel in "monophonic playing".
A channel needs to be played monophonic if this channel has been set
monophonic by basic channel API.(see fluid_synth_polymono.c).
A channel needs also to be played monophonic if it has been set
polyphonic and legato pedal is On.
When in "monophonic playing" only one note at a time can be played in
a staccato or legato manner.
------------------------------------------------------------------------------*/
int fluid_synth_noteon_mono(fluid_synth_t* synth, int chan, int key, int vel);
int fluid_synth_noteoff_monopoly(fluid_synth_t* synth, int chan, int key,
char Mono);
int
fluid_synth_noteon_mono_legato(fluid_synth_t* synth, int chan,
int fromkey, int
tokey, int vel);
/**
* Send a note-on event to a FluidSynth object in "monophonic playing".
* Please see the description above about "monophonic playing".
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param key MIDI note number (0-127)
* @param vel MIDI velocity (0-127)
* @return FLUID_OK on success, FLUID_FAILED otherwise
*/
int
fluid_synth_noteon_mono_LOCAL(fluid_synth_t* synth, int chan, int key, int vel)
{
int status;
char iPrev;
fluid_channel_t* channel = synth->channel[chan];;
/* Add note to the monophonic list */
iPrev = fluid_channel_add_monolist(channel,(unsigned char)key,
(unsigned char)vel);
/* legato/staccato playing detection */
if(channel->nNotes >= 2) { /* legato playing */
/* legato from iPrev to key */
/* the voices from iPrev key number are to be used to play key
number */
status = fluid_synth_noteon_mono_legato(synth, chan,
channel->monolist[iPrev].note, key, vel);
}
/* staccato playing */
else status = fluid_synth_noteon_mono(synth, chan, key, vel);
return status;
}
/**
* Send a note-off event to a FluidSynth object in "monophonic playing".
* Please see the description above about "monophonic playing".
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param key MIDI note number (0-127)
* @return FLUID_OK on success, FLUID_FAILED otherwise
*/
int
fluid_synth_noteoff_mono_LOCAL(fluid_synth_t* synth, int chan, int key)
{
int status;
short i,iPrev;
fluid_channel_t* channel = synth->channel[chan];;
/* search the note in monophonic list */
i=fluid_channel_search_monolist(channel, (unsigned char)key);
if (i >= 0) { /* the note is in monophonic list */
/* Remove note from the monophonic list */
iPrev = fluid_channel_rem_monolist(channel,i);
/* legato playing detection */
if(channel->nNotes) { /* the list contains others notes */
if(iPrev >=0) { /* legato playing detection */
/* legato from key to iPrev key */
/* the voices from key number are to be used to
play iPrev key number. */
status = fluid_synth_noteon_mono_legato(synth,
chan,
key,
channel->monolist[iPrev].note,
channel->monolist[iPrev].vel);
}
/* else the note doesn't need to be played off */
else status = FLUID_OK;
}
else { /* the monophonic list is empty */
/* play the monophonic note noteoff and eventually held
by sustain only (R2) */
status = fluid_synth_noteoff_monopoly(synth, chan, key,
1);
}
}
else { /* the note is not found in the list so the note will
be played On when we was in polyphonic playing */
/* play the noteoff as for polyphonic */
status = fluid_synth_noteoff_monopoly(synth, chan, key,
0);
}
return status;
}
/*----------------------------------------------------------------------------
staccato playing
-----------------------------------------------------------------------------*/
/**
* noteon for monophonic note.
* Please see the description above about "monophonic playing".
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param key MIDI note number (0-127)
* @param vel MIDI velocity (0-127)
* @return FLUID_OK on success, FLUID_FAILED otherwise
*/
int
fluid_synth_noteon_mono(fluid_synth_t* synth, int chan, int key, int vel)
{
fluid_channel_t* channel = synth->channel[chan];
/* Before playing a new note, il a previous monophonic note is currently
sustained it needs to be released */
fluid_synth_release_voice_on_same_note_LOCAL(synth,chan,
channel->key_sustained);
/* The note needs to be played by voices allocation */
return fluid_preset_noteon(channel->preset, synth, chan, key, vel);
}
/**
* noteoff for a polyphonic or monophonic note
* Please see the description above about "monophonic playing".
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param key MIDI note number (0-127)
* @param Mono, 1 noteoff on monophonic note.
* 0 noteoff on polyphonic note
* @return FLUID_OK on success, FLUID_FAILED otherwise
* Note: On return, on monophonic, sustained note needs to be remembered
* in key_sustained.
* On noteon for a monophonic note if a previous monophonic note is sustained
* it will be released. Remembering is done here on noteOff.
*/
int
fluid_synth_noteoff_monopoly(fluid_synth_t* synth, int chan, int key,
char Mono)
{
int status = FLUID_FAILED;
fluid_voice_t* voice;
int i, IsSustained;
fluid_channel_t* channel = synth->channel[chan];
/* Key_sustained is prepared to return no note sustained (-1) */
if (Mono) channel->key_sustained = -1; /* no mono note sustained */
/* noteoff for all voices with same chan and same key */
for (i = 0; i < synth->polyphony; i++) {
voice = synth->voice[i];
if (_ON(voice) && (voice->chan == chan) && (voice->key == key))
{
if (synth->verbose) {
int used_voices = 0;
int k;
for (k = 0; k < synth->polyphony; k++) {
if (!_AVAILABLE(synth->voice[k])) {
used_voices++;
}
}
FLUID_LOG(FLUID_INFO,
"noteoff\t%d\t%d\t%d\t%05d\t%.3f\t%d",
voice->chan, voice->key, 0,
voice->id,
(fluid_curtime() -
synth->start) / 1000.0f,
used_voices);
} /* if verbose */
IsSustained = fluid_voice_noteoff(voice);
/* noteoff on monophonic note */
/* Key remembering if the note is sustained */
if(Mono && IsSustained) channel->key_sustained = key;
status = FLUID_OK;
} /* if voice on */
} /* for all voices */
return status;
}
/*----------------------------------------------------------------------------
legato playing
-----------------------------------------------------------------------------*/
int fluid_synth_noteon_mono_legato_retrigger(fluid_synth_t* synth, int chan,
int fromkey, int
tokey, int vel);
int fluid_synth_noteon_mono_legato_multi_retrigger(fluid_synth_t* synth, int
chan,
int fromkey, int
tokey, int vel);
int fluid_synth_noteon_mono_legato_single_trigger0(fluid_synth_t* synth, int
chan,
int fromkey, int
tokey, int vel);
fluid_synth_noteon_mono_legato_single_trigger1(fluid_synth_t* synth, int chan,
int fromkey, int
tokey, int vel);
/**
* noteon for monophonic note played legato.
* Please see the description above about "monophonic playing".
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param fromkey MIDI note number (0-127)
* @param tokey MIDI note number (0-127)
* @param vel MIDI velocity (0-127)
* @return FLUID_OK on success, FLUID_FAILED otherwise
* Note: The voices with key 'fromkey' are to be used to play key 'tokey'.
*/
int
fluid_synth_noteon_mono_legato(fluid_synth_t* synth, int chan,
int fromkey, int
tokey, int vel)
{
int status;
unsigned char legatomode = GetChanLegatoMode(synth->channel[chan]);
switch (legatomode)
{
case RETRIGGER: /* mode 0 */
status=
fluid_synth_noteon_mono_legato_retrigger(synth,chan,fromkey,
tokey,vel);
break;
case MULTI_RETRIGGER: /* mode 1 */
status =
fluid_synth_noteon_mono_legato_multi_retrigger(synth,chan,fromkey,
tokey,vel);
break;
case SINGLE_TRIGGER_0: /* mode 2 */
status=
fluid_synth_noteon_mono_legato_single_trigger0(synth,chan,fromkey,
tokey,vel);
break;
case SINGLE_TRIGGER_1: /* mode 3 */
status=
fluid_synth_noteon_mono_legato_single_trigger1(synth,chan,fromkey,
tokey,vel);
break;
default:
FLUID_LOG(FLUID_WARN, "Failed to execute legato mode:
%d",legatomode);
status = FLUID_FAILED;
}
return status;
}
/*-----------------------------------------------------------------------------
/* Mode 0: retrigger */
int fluid_synth_noteon_mono_legato_retrigger(fluid_synth_t* synth, int chan,
int fromkey, int
tokey, int vel)
{
fluid_channel_t* channel = synth->channel[chan];
fluid_voice_t* voice;
int i, status ;
/* Mode 0: retrigger (with crossfading between release and attack) */
/* Release the fromkey note */
for (i = 0; i < synth->polyphony; i++) {
/* search fromkey voice: only those who don't have 'note off' */
voice = synth->voice[i];
if (_ON(voice) && (voice->chan == chan) &&
(voice->key == fromkey)){
fluid_update_release(voice);
}
}
/* tokey note needs to be played by voices allocation */
synth->fromkey = fromkey; /* portamento fromkey */
status = fluid_preset_noteon(channel->preset, synth, chan, tokey, vel);
/* When fromkey is set to -1 , portamento is disabled even if portamento
pedal is pressed. Once portamento is triggered by
fluid_preset_noteon(), fromkey is set to -1 to disable
portamento for the next fluid_preset_noteon. This is very useful has the
first note (n1) of a legato passage (n1,n2,n3,..) will be always without
portamento but not the following notes (n2,n3,..) */
synth->fromkey = -1; /* disable portamento */
return status;
}
/*-----------------------------------------------------------------------------
/* Mode 1: multi_retrigger */
int
fluid_synth_noteon_mono_legato_multi_retrigger(fluid_synth_t* synth, int chan,
int fromkey, int
tokey, int vel)
{
fluid_channel_t* channel = synth->channel[chan];
unsigned char found = 0;
fluid_voice_t* voice;
int i, status = FLUID_OK;
/* Mode 0: retrigger (with crossfading between release and attack) */
for (i = 0; i < synth->polyphony; i++) {
/* search fromkey voice: only those who don't have 'note off' */
voice = synth->voice[i];
if (_ON(voice) && (voice->chan == chan) &&
(voice->key == fromkey)){
found = 1;
/* Skip in attack section */
fluid_update_multi_retrigger_attack(voice,tokey,vel);
/* Start portamento if enabled */
if( fluid_channel_portamento(channel))
/* Send portamento parameters to the voice dsp
*/
fluid_voice_update_portamento(voice,fromkey,tokey);
}
}
if(!found) /* fromkey note have finished */
{ /* The note needs to be played by voices allocation */
int i, status ;
synth->fromkey = fromkey; /* portamento fromkey */
status =
fluid_preset_noteon(channel->preset,synth,chan,tokey,vel);
synth->fromkey = -1; /* disable portamento */
}
return status;
}
/*-----------------------------------------------------------------------------
/* Mode 2: single_trigger_0 */
int
fluid_synth_noteon_mono_legato_single_trigger0(fluid_synth_t* synth, int chan,
int fromkey, int
tokey, int vel)
{
fluid_channel_t* channel = synth->channel[chan];
unsigned char found = 0;
fluid_voice_t* voice;
int i, status = FLUID_OK;
/* Mode 0: retrigger (with crossfading between release and attack) */
for (i = 0; i < synth->polyphony; i++) {
/* search fromkey voice: only those who don't have 'note off' */
voice = synth->voice[i];
if (_ON(voice) && (voice->chan == chan) &&
(voice->key == fromkey)){
found = 1;
fluid_update_single_trigger0(voice,fromkey,tokey,vel);
/* Start portamento if enabled */
if( fluid_channel_portamento(channel))
/* Send portamento parameters to the voice dsp
*/
fluid_voice_update_portamento(voice,fromkey,tokey);
}
}
if(!found) /* fromkey note have finished */
{ /* The note needs to be played by voices allocation */
synth->fromkey = fromkey; /* portamento fromkey */
status =
fluid_preset_noteon(channel->preset,synth,chan,tokey,vel);
synth->fromkey = -1; /* disable portamento */
}
return status;
}
/*-----------------------------------------------------------------------------
/* Mode 3: single_trigger_1 */
int
fluid_synth_noteon_mono_legato_single_trigger1(fluid_synth_t* synth, int chan,
int fromkey, int
tokey, int vel)
{
fluid_channel_t* channel = synth->channel[chan];
unsigned char found = 0;
fluid_voice_t* voice;
int i, status = FLUID_OK;
/* Mode 0: retrigger (with crossfading between release and attack) */
for (i = 0; i < synth->polyphony; i++) {
/* search fromkey voice: only those who don't have 'note off' */
voice = synth->voice[i];
if (_ON(voice) && (voice->chan == chan) &&
(voice->key == fromkey)){
found = 1;
fluid_update_single_trigger1(voice,fromkey,tokey,vel);
/* Start portamento if enabled */
if( fluid_channel_portamento(channel))
/* Send portamento parameters to the voice dsp
*/
fluid_voice_update_portamento(voice,fromkey,tokey);
}
}
if(!found) /* fromkey note have finished */
{ /* The note needs to be played by voices allocation */
synth->fromkey = fromkey; /* portamento fromkey */
status =
fluid_preset_noteon(channel->preset,synth,chan,tokey,vel);
synth->fromkey = -1; /* disable portamento */
}
return status;
}
_______________________________________________
fluid-dev mailing list
fluid-dev@nongnu.org
https://lists.nongnu.org/mailman/listinfo/fluid-dev