drmr2/drmr.c

327 lines
8.4 KiB
C
Raw Normal View History

2012-02-07 12:52:59 +01:00
/* drmr.c
* LV2 DrMr plugin
* Copyright 2012 Nick Lanham <nick@afternight.org>
*
* Public License v3. source code is available at
* <http://github.com/nicklan/drmr>
* THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2012-02-07 12:00:07 +01:00
#include <math.h>
#include "drmr.h"
2012-02-07 10:59:24 +01:00
#include "drmr_hydrogen.h"
int load_sample(char* path, drmr_sample* samp) {
SNDFILE* sndf;
int size;
2012-02-07 09:31:51 +01:00
//printf("Loading: %s\n",path);
samp->active = 0;
memset(&(samp->info),0,sizeof(SF_INFO));
sndf = sf_open(path,SFM_READ,&(samp->info));
if (!sndf) {
fprintf(stderr,"Failed to open sound file: %s - %s\n",path,sf_strerror(sndf));
return 1;
}
if (samp->info.channels > 2) {
fprintf(stderr, "File has too many channels. Can only handle mono/stereo samples\n");
return 1;
}
size = samp->info.frames * samp->info.channels;
samp->limit = size;
samp->data = malloc(size*sizeof(float));
if (!samp->data) {
fprintf(stderr,"Failed to allocate sample memory for %s\n",path);
return 1;
}
sf_read_float(sndf,samp->data,size);
sf_close(sndf);
return 0;
}
2012-02-07 12:00:07 +01:00
static void* load_thread(void* arg) {
DrMr* drmr = (DrMr*)arg;
pthread_mutex_lock(&drmr->load_mutex);
for(;;) {
pthread_cond_wait(&drmr->load_cond,
&drmr->load_mutex);
int request = (int)floorf(*(drmr->kitReq));
if (request >= drmr->kits->num_kits) {
int os = drmr->num_samples;
drmr->num_samples = 0;
if (os > 0) free_samples(drmr->samples,os);
drmr->samples = NULL;
} else
load_hydrogen_kit(drmr,drmr->kits->kits[request].path);
drmr->curKit = request;
2012-02-07 12:00:07 +01:00
}
pthread_mutex_unlock(&drmr->load_mutex);
return 0;
}
static LV2_Handle
instantiate(const LV2_Descriptor* descriptor,
double rate,
const char* bundle_path,
const LV2_Feature* const* features) {
int i;
DrMr* drmr = malloc(sizeof(DrMr));
drmr->map = NULL;
drmr->num_samples = 0;
2012-02-07 12:00:07 +01:00
if (pthread_mutex_init(&drmr->load_mutex, 0)) {
fprintf(stderr, "Could not initialize load_mutex.\n");
free(drmr);
return 0;
}
if (pthread_cond_init(&drmr->load_cond, 0)) {
fprintf(stderr, "Could not initialize load_cond.\n");
free(drmr);
return 0;
}
if (pthread_create(&drmr->load_thread, 0, load_thread, drmr)) {
fprintf(stderr, "Could not initialize loading thread.\n");
free(drmr);
return 0;
}
// Map midi uri
while(*features) {
if (!strcmp((*features)->URI, LV2_URI_MAP_URI)) {
drmr->map = (LV2_URI_Map_Feature *)((*features)->data);
drmr->uris.midi_event = drmr->map->uri_to_id
(drmr->map->callback_data,
"http://lv2plug.in/ns/ext/event",
"http://lv2plug.in/ns/ext/midi#MidiEvent");
}
features++;
}
if (!drmr->map) {
2012-02-07 12:54:42 +01:00
fprintf(stderr, "LV2 host does not support uri-map.\n");
free(drmr);
return 0;
}
2012-02-07 10:59:24 +01:00
drmr->kits = scan_kits();
if (!drmr->kits) {
fprintf(stderr, "No drum kits found\n");
free(drmr);
return 0;
}
drmr->samples = NULL; // prevent attempted freeing in load
2012-02-07 10:59:24 +01:00
load_hydrogen_kit(drmr,drmr->kits->kits->path);
2012-02-07 12:00:07 +01:00
drmr->curKit = 0;
2012-02-07 09:31:51 +01:00
drmr->gains = malloc(16*sizeof(float*));
for(i = 0;i<16;i++) drmr->gains[i] = NULL;
return (LV2_Handle)drmr;
}
static void
connect_port(LV2_Handle instance,
uint32_t port,
void* data) {
DrMr* drmr = (DrMr*)instance;
switch ((DrMrPortIndex)port) {
case DRMR_MIDI:
drmr->midi_port = (LV2_Event_Buffer*)data;
break;
case DRMR_LEFT:
drmr->left = (float*)data;
break;
case DRMR_RIGHT:
drmr->right = (float*)data;
break;
2012-02-07 12:00:07 +01:00
case DRMR_KITNUM:
if(data) drmr->kitReq = (float*)data;
break;
2012-02-07 09:31:51 +01:00
case DRMR_GAIN_ONE:
if (data) drmr->gains[0] = (float*)data;
break;
case DRMR_GAIN_TWO:
if (data) drmr->gains[1] = (float*)data;
break;
case DRMR_GAIN_THREE:
if (data) drmr->gains[2] = (float*)data;
break;
case DRMR_GAIN_FOUR:
if (data) drmr->gains[3] = (float*)data;
break;
case DRMR_GAIN_FIVE:
if (data) drmr->gains[4] = (float*)data;
break;
case DRMR_GAIN_SIX:
if (data) drmr->gains[5] = (float*)data;
break;
case DRMR_GAIN_SEVEN:
if (data) drmr->gains[6] = (float*)data;
break;
case DRMR_GAIN_EIGHT:
if (data) drmr->gains[7] = (float*)data;
break;
case DRMR_GAIN_NINE:
if (data) drmr->gains[8] = (float*)data;
break;
case DRMR_GAIN_TEN:
if (data) drmr->gains[9] = (float*)data;
break;
case DRMR_GAIN_ELEVEN:
if (data) drmr->gains[10] = (float*)data;
break;
case DRMR_GAIN_TWELVE:
if (data) drmr->gains[11] = (float*)data;
break;
case DRMR_GAIN_THIRTEEN:
if (data) drmr->gains[12] = (float*)data;
break;
case DRMR_GAIN_FOURTEEN:
if (data) drmr->gains[13] = (float*)data;
break;
case DRMR_GAIN_FIFTEEN:
if (data) drmr->gains[14] = (float*)data;
break;
case DRMR_GAIN_SIXTEEN:
if (data) drmr->gains[15] = (float*)data;
break;
default:
break;
}
}
static void activate(LV2_Handle instance) { }
static void run(LV2_Handle instance, uint32_t n_samples) {
2012-02-07 12:00:07 +01:00
int i,kitInt;
DrMr* drmr = (DrMr*)instance;
2012-02-07 12:00:07 +01:00
kitInt = (int)floorf(*(drmr->kitReq));
if (kitInt != drmr->curKit) // requested a new kit
2012-02-07 12:00:07 +01:00
pthread_cond_signal(&drmr->load_cond);
LV2_Event_Iterator eit;
if (lv2_event_begin(&eit,drmr->midi_port)) { // if we have any events
LV2_Event *cur_ev;
uint8_t* data;
while (lv2_event_is_valid(&eit)) {
cur_ev = lv2_event_get(&eit,&data);
if (cur_ev->type == drmr->uris.midi_event) {
int channel = *data & 15;
switch ((*data) >> 4) {
case 8: // ignore note-offs for now, should probably be a setting
//if (drmr->cur_samp) drmr->cur_samp->active = 0;
break;
case 9: {
uint8_t nn = data[1];
nn-=60; // middle c is our root note (setting?)
// need to mutex this to avoid getting the samples array
// changed after the check that the midi-note is valid
pthread_mutex_lock(&drmr->load_mutex);
if (nn >= 0 && nn < drmr->num_samples) {
drmr->samples[nn].active = 1;
drmr->samples[nn].offset = 0;
}
pthread_mutex_unlock(&drmr->load_mutex);
break;
}
default:
printf("Unhandeled status: %i\n",(*data)>>4);
}
2012-02-07 09:31:51 +01:00
} else printf("unrecognized event\n");
lv2_event_increment(&eit);
2012-02-07 09:31:51 +01:00
}
}
for(i = 0;i<n_samples;i++) {
drmr->left[i] = 0.0f;
drmr->right[i] = 0.0f;
}
pthread_mutex_lock(&drmr->load_mutex);
for (i = 0;i < drmr->num_samples;i++) {
int pos,lim;
drmr_sample* cs = drmr->samples+i;
if (cs->active) {
float gain;
if (i < 16)
gain = *(drmr->gains[i]);
else
gain = 1.0f;
if (cs->info.channels == 1) { // play mono sample
lim = (n_samples < (cs->limit - cs->offset)?n_samples:(cs->limit-cs->offset));
for(pos = 0;pos < lim;pos++) {
drmr->left[pos] += cs->data[cs->offset]*gain;
drmr->right[pos] += cs->data[cs->offset]*gain;
cs->offset++;
}
} else { // play stereo sample
lim = (cs->limit-cs->offset)/cs->info.channels;
if (lim > n_samples) lim = n_samples;
for (pos=0;pos<lim;pos++) {
drmr->left[pos] += cs->data[cs->offset++]*gain;
drmr->right[pos] += cs->data[cs->offset++]*gain;
}
}
if (cs->offset >= cs->limit) cs->active = 0;
}
}
pthread_mutex_unlock(&drmr->load_mutex);
}
static void deactivate(LV2_Handle instance) {}
static void cleanup(LV2_Handle instance) {
2012-02-07 21:30:32 +01:00
DrMr* drmr = (DrMr*)instance;
pthread_cancel(drmr->load_thread);
pthread_join(drmr->load_thread, 0);
if (drmr->num_samples > 0)
free_samples(drmr->samples,drmr->num_samples);
free(drmr->gains);
free(instance);
}
const void* extension_data(const char* uri) {
return NULL;
}
static const LV2_Descriptor descriptor = {
DRMR_URI,
instantiate,
connect_port,
activate,
run,
deactivate,
cleanup,
extension_data
};
LV2_SYMBOL_EXPORT
const LV2_Descriptor*
lv2_descriptor(uint32_t index)
{
switch (index) {
case 0:
return &descriptor;
default:
return NULL;
}
}