Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
307 lines (270 sloc) 8.74 KB
/*
* so-kl5.c
*
* Copyright (C) 2011 - Jeremy Salwen
* Copyright (C) 2010 - 50m30n3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "so-kl5.h"
inline float sustain_scale(float input) {
return 0.6+powf( input, 0.4)*0.4;
}
void runSO_kl5( LV2_Handle arg, uint32_t nframes ) {
so_kl5* so=(so_kl5*)arg;
lv2_event_begin(&so->in_iterator,so->MidiIn);
float **strings=so->strings;
unsigned int* stringpos=so->stringpos;
unsigned int* stringlength=so->stringlength;
float* tempstring=so->tempstring;
float* stringcutoff=so->stringcutoff;
float* outbuffer=so->output;
int * status=so->status;
int i, note;
float sample, damp;
if(*so->controlmode_p > 0) {
so->volume=*so->volume_p;
so->fcutoff=*so->cutoff_p;
so->sattack=*so->attack_p;
so->freso=(*so->resonance_p)*(1.0 - (*so->cutoff_p));
so->ssustain=sustain_scale(*so->sustain_p);
}
for( i=0; i<nframes; i++ ) {
while(lv2_event_is_valid(&so->in_iterator)) {
uint8_t* data;
LV2_Event* event= lv2_event_get(&so->in_iterator,&data);
if (event->type == 0) {
so->event_ref->lv2_event_unref(so->event_ref->callback_data, event);
} else if(event->type==so->midi_event_id) {
if(event->frames > i) {
break;
} else {
const uint8_t* evt=(uint8_t*)data;
if((evt[0]&MIDI_CHANNELMASK)==(int) (*so->channel_p)) {
if((evt[0]&MIDI_COMMANDMASK)==MIDI_NOTEON) {
note = evt[1];
if( ( note >= BASENOTE ) && ( note < BASENOTE+NUMNOTES ) )
{
note -= BASENOTE;
status[note] = 1;
int j;
for( j=0; j<stringlength[note]; j++ )
{
tempstring[j] = ((float)rand()/(float)RAND_MAX)*2.0-1.0;
}
float velocity=evt[2];
float freq = stringcutoff[note] * 0.25 + velocity/127.0 * 0.2 + so->sattack + 0.1;
for( j=0; j<30; j++ )
{
tempstring[0] = tempstring[0]*freq + tempstring[stringlength[note]-1]*(1.0-freq);
int k;
for( k=1; k<stringlength[note]; k++ )
{
tempstring[k] = tempstring[k]*freq + tempstring[(k-1)%stringlength[note]]*(1.0-freq);
}
}
float avg = 0.0;
for( j=0; j<stringlength[note]; j++ )
{
avg += tempstring[j];
}
avg /= stringlength[note];
float scale = 0.0;
for( j=0; j<stringlength[note]; j++ )
{
tempstring[j] -= avg;
if( fabs( tempstring[j] ) > scale )
scale = fabs( tempstring[j] );
}
float min = 10.0;
int minpos = 0;
for( j=0; j<stringlength[note]; j++ )
{
tempstring[j] /= scale;
if( fabs( tempstring[j] ) + fabs( tempstring[j] - tempstring[j-1] ) * 5.0 < min )
{
min = fabs( tempstring[j] ) + fabs( tempstring[j] - tempstring[j-1] ) * 5.0;
minpos = j;
}
}
float vol = velocity/256.0;
for( j=0; j<stringlength[note]; j++ )
{
strings[note][(stringpos[note]+j)%stringlength[note]] += tempstring[(j+minpos)%stringlength[note]]*vol;
}
}
}
else if((evt[0]&MIDI_COMMANDMASK)==MIDI_NOTEOFF ) {
note = evt[1];
if( ( note >= BASENOTE ) && ( note < BASENOTE+NUMNOTES ) )
{
note -= BASENOTE;
status[note] = 0;
}
}
else if((*so->controlmode_p<=0) && (evt[0]&MIDI_COMMANDMASK)==MIDI_CONTROL ) {
if( evt[1] == 74 ) {
unsigned int cutoff =evt[2];
so->fcutoff = (cutoff+5.0)/400.0;
} else if( evt[1]== 71 ) {
unsigned int resonance = evt[2];
so->freso = (resonance/140.0)*(1.0-so->fcutoff);
} else if( evt[1]== 73 ) {
unsigned int attack = evt[2];
so->sattack = (attack+5.0)/800.0;
} else if( evt[1] == 7 ) {
so->volume = evt[2];
} else if( evt[1]== 1 ||evt[1]==64) {
unsigned int sustain =evt[2];
so->ssustain =sustain_scale(sustain/127.0);
}
}
}
}
}
lv2_event_increment(&so->in_iterator);
}
sample = 0.0;
for( note=0; note<NUMNOTES; note++ )
{
damp = stringcutoff[note];
if( stringpos[note] > 0 )
strings[note][stringpos[note]] = strings[note][stringpos[note]]*damp +
strings[note][stringpos[note]-1]*(1.0-damp);
else
strings[note][stringpos[note]] = strings[note][stringpos[note]]*damp +
strings[note][stringlength[note]-1]*(1.0-damp);
damp = ((float)note/(float)NUMNOTES)*0.0049995 + 0.0049995;
if( status[note] == 0 )
strings[note][stringpos[note]] *= 0.8+so->ssustain*0.19+damp;
else
strings[note][stringpos[note]] *= 0.99+damp;
sample += strings[note][stringpos[note]];
}
for( note=0; note<NUMNOTES; note++ )
{
if( fabs( strings[note][stringpos[note]] ) <= 0.00001 )
strings[note][stringpos[note]] = 0.0;
stringpos[note]++;
if( stringpos[note] >= stringlength[note] ) stringpos[note] = 0;
}
so->lpval += (sample-so->lplast) * so->fcutoff;
so->lplast += so->lpval;
so->lpval *= so->freso;
sample = so->lplast;
outbuffer[i] = sample * (so->volume/127.0);
}
}
LV2_Handle instantiateSO_kl5(const LV2_Descriptor *descriptor,double s_rate, const char *path,const LV2_Feature * const* features) {
so_kl5* so=malloc(sizeof(so_kl5));
LV2_URI_Map_Feature *map_feature;
const LV2_Feature * const * ft;
for (ft = features; *ft; ft++) {
if (!strcmp((*ft)->URI, "http://lv2plug.in/ns/ext/uri-map")) {
map_feature = (*ft)->data;
so->midi_event_id = map_feature->uri_to_id(
map_feature->callback_data,
"http://lv2plug.in/ns/ext/event",
"http://lv2plug.in/ns/ext/midi#MidiEvent");
} else if (!strcmp((*ft)->URI, "http://lv2plug.in/ns/ext/event")) {
so->event_ref = (*ft)->data;
}
}
puts( "SO-666 v.1.0 by 50m30n3 2009" );
unsigned int cutoff,resonance,sustain,attack;
sustain = 0;
cutoff = 64;
resonance = 100;
attack=4;
so->volume = 100;
so->lplast=0;
so->lpval=0;
so->fcutoff = (cutoff+5.0)/400.0;
so->sattack = (attack+5.0)/800.0;
so->freso = (resonance/160.0)*(1.0-so->fcutoff);
so->ssustain = 0.6+powf( sustain/127.0, 0.4);
int note;
for( note=0; note<NUMNOTES; note++ ) {
float freq = 440.0*powf( 2.0, (note+BASENOTE-69) / 12.0 );
so->stringcutoff[note] = 0.5 + pow( (double)note / (double)NUMNOTES, 0.5 ) * 0.45;
int length = round( (float)s_rate / freq );
so->stringlength[note] = length;
so->strings[note] = malloc( length * sizeof( float ) );
if( so->strings[note] == NULL )
{
fputs( "Error allocating memory\n", stderr );
return 0;
}
int i;
for( i=0; i<length; i++ )
{
so->strings[note][i] = 0.0;
}
so->stringpos[note] = 0;
so->status[note] = 0;
}
float freq = 440.0*powf( 2.0, (BASENOTE-69) / 12.0 );
float length = (float)s_rate / freq;
so->tempstring = malloc( length * sizeof( float ) );
if( so->tempstring == NULL )
{
fputs( "Error allocating memory\n", stderr );
return 0;
}
return so;
}
void cleanupSO_kl5(LV2_Handle instance) {
so_kl5* so=(so_kl5*)instance;
free(so->tempstring);
int note;
for(note=0; note<NUMNOTES; note++ )
{
free( so->strings[note] );
}
free(so);
}
void connectPortSO_kl5(LV2_Handle instance, uint32_t port, void *data_location) {
so_kl5* so=(so_kl5*) instance;
switch(port) {
case KL5_PORT_OUTPUT:
so->output=data_location;
break;
case KL5_PORT_MIDI:
so->MidiIn=data_location;
break;
case KL5_PORT_CONTROLMODE:
so->controlmode_p=data_location;
break;
case KL5_PORT_VOLUME:
so->volume_p=data_location;
break;
case KL5_PORT_SUSTAIN:
so->sustain_p=data_location;
break;
case KL5_PORT_CUTOFF:
so->cutoff_p=data_location;
break;
case KL5_PORT_RESONANCE:
so->resonance_p=data_location;
break;
case KL5_PORT_ATTACK:
so->attack_p=data_location;
break;
case KL5_PORT_CHANNEL:
so->channel_p=data_location;
break;
default:
fputs("Warning, unconnected port!\n",stderr);
}
}
Something went wrong with that request. Please try again.