From 45b2eeae22374223d5c5684ff787d1338a640c40 Mon Sep 17 00:00:00 2001 From: Nick Lanham Date: Mon, 13 Feb 2012 16:11:30 +0100 Subject: [PATCH] Lots of fixes (multi-layer, ui): - Fix ui to properly re-init sample table - Fix ui to only adjust existing sliders - Actually load multi-layer kits - Play correct layer for multi-layer --- drmr.c | 31 +++++++++++-- drmr.h | 14 +++++- drmr_hydrogen.c | 108 ++++++++++++++++++++++++++++++++------------ drmr_hydrogen.h | 2 +- drmr_ui.c | 117 ++++++++++++++++++++++++++---------------------- 5 files changed, 185 insertions(+), 87 deletions(-) diff --git a/drmr.c b/drmr.c index 9ec093f..5cf7bba 100644 --- a/drmr.c +++ b/drmr.c @@ -140,6 +140,26 @@ connect_port(LV2_Handle instance, } } +static inline void layer_to_sample(drmr_sample *sample, float gain) { + int i; + float mapped_gain = (1-(gain/GAIN_MIN)); + if (mapped_gain > 1.0f) mapped_gain = 1.0f; + for(i = 0;i < sample->layer_count;i++) { + if (sample->layers[i].min <= mapped_gain && + (sample->layers[i].max > mapped_gain || + sample->layers[i].max == 1 && mapped_gain == 1)) { + sample->limit = sample->layers[i].limit; + sample->info = sample->layers[i].info; + sample->data = sample->layers[i].data; + return; + } + } + fprintf(stderr,"Couldn't find layer for gain %f in sample\n\n",gain); + sample->limit = 0; + sample->info = NULL; + sample->data = NULL; +} + #define DB3SCALE -0.8317830986718104f #define DB3SCALEPO 1.8317830986718104f // taken from lv2 example amp plugin @@ -172,6 +192,11 @@ static void run(LV2_Handle instance, uint32_t n_samples) { // changed after the check that the midi-note is valid pthread_mutex_lock(&drmr->load_mutex); if (nn >= 0 && nn < drmr->num_samples) { + if (drmr->samples[nn].layer_count > 0) + layer_to_sample(drmr->samples+nn,*(drmr->gains[nn])); + if (drmr->samples[nn].limit == 0) { + printf("Fail at: %i for %f\n",nn,*drmr->gains[nn]); + } drmr->samples[nn].active = 1; drmr->samples[nn].offset = 0; } @@ -195,7 +220,7 @@ static void run(LV2_Handle instance, uint32_t n_samples) { for (i = 0;i < drmr->num_samples;i++) { int pos,lim; drmr_sample* cs = drmr->samples+i; - if (cs->active) { + if (cs->active && (cs->limit > 0)) { float coef_right, coef_left; if (i < 32) { float gain = DB_CO(*(drmr->gains[i])); @@ -208,7 +233,7 @@ static void run(LV2_Handle instance, uint32_t n_samples) { coef_right = coef_left = 1.0f; } - if (cs->info.channels == 1) { // play mono sample + 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]*coef_left; @@ -216,7 +241,7 @@ static void run(LV2_Handle instance, uint32_t n_samples) { cs->offset++; } } else { // play stereo sample - lim = (cs->limit-cs->offset)/cs->info.channels; + lim = (cs->limit-cs->offset)/cs->info->channels; if (lim > n_samples) lim = n_samples; for (pos=0;posleft[pos] += cs->data[cs->offset++]*coef_left; diff --git a/drmr.h b/drmr.h index 22fdb05..f55c2ff 100644 --- a/drmr.h +++ b/drmr.h @@ -41,10 +41,21 @@ typedef struct { // libsndfile stuff typedef struct { - SF_INFO info; + float min; + float max; + + SF_INFO *info; + uint32_t limit; + float* data; +} drmr_layer; + +typedef struct { + SF_INFO *info; char active; uint32_t offset; uint32_t limit; + uint32_t layer_count; + drmr_layer *layers; float* data; } drmr_sample; @@ -52,6 +63,7 @@ typedef struct { #define DRMR_URI "http://github.com/nicklan/drmr" #define GAIN_MIN -60.0f +#define GAIN_MAX 6.0f typedef enum { DRMR_MIDI = 0, diff --git a/drmr_hydrogen.c b/drmr_hydrogen.c index 67cba7e..8f77a75 100644 --- a/drmr_hydrogen.c +++ b/drmr_hydrogen.c @@ -38,9 +38,9 @@ static char* default_drumkit_locations[] = { struct instrument_layer { char* filename; - int min; - int max; - int gain; + float min; + float max; + float gain; struct instrument_layer *next; }; @@ -48,7 +48,7 @@ struct instrument_info { int id; char* filename; char* name; - int gain; + float gain; struct instrument_layer *layers; struct instrument_info *next; // maybe pan/vol/etc.. @@ -124,11 +124,11 @@ endElement(void *userData, const char *name) if (!strcmp(name,"filename")) info->cur_layer->filename = strdup(info->cur_buf); if (!strcmp(name,"min")) - info->cur_layer->min = atoi(info->cur_buf); + info->cur_layer->min = atof(info->cur_buf); if (!strcmp(name,"max")) - info->cur_layer->max = atoi(info->cur_buf); + info->cur_layer->max = atof(info->cur_buf); if (!strcmp(name,"gain")) - info->cur_layer->gain = atoi(info->cur_buf); + info->cur_layer->gain = atof(info->cur_buf); } if (info->in_instrument) { @@ -138,7 +138,7 @@ endElement(void *userData, const char *name) info->counted_cur_inst = 1; } } - else { + else if (!info->in_layer) { if (!strcmp(name,"id")) info->cur_instrument->id = atoi(info->cur_buf); if (!strcmp(name,"filename")) @@ -310,42 +310,53 @@ kits* scan_kits() { } void free_samples(drmr_sample* samples, int num_samples) { - int i; - for (i=0;iactive = 0; - - memset(&(samp->info),0,sizeof(SF_INFO)); - sndf = sf_open(path,SFM_READ,&(samp->info)); + layer->info = malloc(sizeof(SF_INFO)); + memset(layer->info,0,sizeof(SF_INFO)); + sndf = sf_open(path,SFM_READ,layer->info); if (!sndf) { fprintf(stderr,"Failed to open sound file: %s - %s\n",path,sf_strerror(sndf)); + free(layer->info); return 1; } - if (samp->info.channels > 2) { + if (layer->info->channels > 2) { fprintf(stderr, "File has too many channels. Can only handle mono/stereo samples\n"); + free(layer->info); return 1; } - size = samp->info.frames * samp->info.channels; - samp->limit = size; - samp->data = malloc(size*sizeof(float)); - if (!samp->data) { + size = layer->info->frames * layer->info->channels; + layer->limit = size; + layer->data = malloc(size*sizeof(float)); + if (!layer->data) { fprintf(stderr,"Failed to allocate sample memory for %s\n",path); + free(layer->info); return 1; } - sf_read_float(sndf,samp->data,size); + sf_read_float(sndf,layer->data,size); sf_close(sndf); return 0; } @@ -406,14 +417,53 @@ int load_hydrogen_kit(DrMr* drmr, char* path) { samples = malloc(num_inst*sizeof(drmr_sample)); cur_i = kit_info.instruments; while(cur_i) { - snprintf(buf,BUFSIZ,"%s/%s",path,cur_i->filename); - if (load_sample(buf,samples+i)) { - fprintf(stderr,"Could not load sample: %s\n",buf); + if (cur_i->filename) { // top level filename, just make one dummy layer + drmr_layer *layer = malloc(sizeof(drmr_layer)); + layer->min = 0; + layer->max = 1; + snprintf(buf,BUFSIZ,"%s/%s",path,cur_i->filename); + if (load_sample(buf,layer)) { + fprintf(stderr,"Could not load sample: %s\n",buf); + // set limit to zero, will never try and play + layer->info = NULL; + layer->limit = 0; + layer->data = NULL; + } + samples[i].layer_count = 0; + samples[i].layers = NULL; samples[i].offset = 0; - // set limit to zero, will never try and play - samples[i].limit = 0; - samples[i].data = NULL; + samples[i].info = layer->info; + samples[i].limit = layer->limit; + samples[i].data = layer->data; + free(layer); + } else { + int layer_count = 0; + int j; + struct instrument_layer *cur_l = cur_i->layers; + while(cur_l) { + layer_count++; + cur_l = cur_l->next; + } + samples[i].layer_count = layer_count; + samples[i].layers = malloc(sizeof(drmr_layer)*layer_count); + cur_l = cur_i->layers; + j = 0; + while(cur_l) { + snprintf(buf,BUFSIZ,"%s/%s",path,cur_l->filename); + if (load_sample(buf,samples[i].layers+j)) { + fprintf(stderr,"Could not load sample: %s\n",buf); + // set limit to zero, will never try and play + samples[i].layers[j].info = NULL; + samples[i].layers[j].limit = 0; + samples[i].layers[j].data = NULL; + } + samples[i].layers[j].min = cur_l->min; + samples[i].layers[j].max = cur_l->max; + j++; + cur_l = cur_l->next; + } } + samples[i].active = 0; i++; cur_i = cur_i->next; } diff --git a/drmr_hydrogen.h b/drmr_hydrogen.h index eb6b8e2..534db9c 100644 --- a/drmr_hydrogen.h +++ b/drmr_hydrogen.h @@ -20,7 +20,7 @@ kits* scan_kits(); void free_samples(drmr_sample* samples, int num_samples); -int load_sample(char* path,drmr_sample* smp); +int load_sample(char* path,drmr_layer* layer); int load_hydrogen_kit(DrMr* drmr, char* path); #endif // DRMR_HYDRO_H diff --git a/drmr_ui.c b/drmr_ui.c index 5d2a5a5..9bf0f28 100644 --- a/drmr_ui.c +++ b/drmr_ui.c @@ -30,11 +30,14 @@ typedef struct { GtkWidget *drmr_widget; GtkTable *sample_table; - GtkComboBoxText *kit_combo; + GtkComboBox *kit_combo; + GtkListStore *kit_store; GtkWidget** gain_sliders; GtkWidget** pan_sliders; int cols; + int samples; + GQuark gain_quark, pan_quark; int curKit; @@ -55,15 +58,12 @@ static void pan_callback(GtkRange* range, gpointer data) { ui->write(ui->controller,pidx+DRMR_PAN_ONE,4,0,&pan); } -static void fill_sample_table(DrMrUi* ui, int samples) { +static void fill_sample_table(DrMrUi* ui, int samples, GtkWidget** gain_sliders, GtkWidget** pan_sliders) { int row = 0; int col = 0; int si; gchar buf[32];; - GtkRequisition req; int rows = (samples/ui->cols); - req.width=500; - req.height=500; gtk_table_resize(ui->sample_table,rows,ui->cols); for(si = 0;siSample %i",si); + sprintf(buf,"Sample %i",(si+1)); frame = gtk_frame_new(buf); gtk_label_set_use_markup(GTK_LABEL(gtk_frame_get_label_widget(GTK_FRAME(frame))),true); @@ -81,8 +81,7 @@ static void fill_sample_table(DrMrUi* ui, int samples) { gain_slider = gtk_vscale_new_with_range(GAIN_MIN,6.0,1.0); g_object_set_qdata (G_OBJECT(gain_slider),ui->gain_quark,GINT_TO_POINTER(si)); g_signal_connect(G_OBJECT(gain_slider),"value-changed",G_CALLBACK(gain_callback),ui); - if (ui->gain_sliders) - ui->gain_sliders[si] = gain_slider; + if (gain_sliders) gain_sliders[si] = gain_slider; gtk_range_set_inverted(GTK_RANGE(gain_slider),true); gtk_scale_set_value_pos(GTK_SCALE(gain_slider),GTK_POS_BOTTOM); gtk_range_set_value(GTK_RANGE(gain_slider),0.0); @@ -94,8 +93,7 @@ static void fill_sample_table(DrMrUi* ui, int samples) { gain_vbox = gtk_vbox_new(false,0); pan_slider = gtk_hscale_new_with_range(-1.0,1.0,0.1); - if (ui->pan_sliders) - ui->pan_sliders[si] = pan_slider; + if (pan_sliders) pan_sliders[si] = pan_slider; gtk_range_set_value(GTK_RANGE(pan_slider),0); g_object_set_qdata (G_OBJECT(pan_slider),ui->pan_quark,GINT_TO_POINTER(si)); gtk_scale_add_mark(GTK_SCALE(pan_slider),0.0,GTK_POS_TOP,NULL); @@ -103,7 +101,6 @@ static void fill_sample_table(DrMrUi* ui, int samples) { pan_label = gtk_label_new("Pan"); pan_vbox = gtk_vbox_new(false,0); - gtk_box_pack_start(GTK_BOX(gain_vbox),gain_slider,true,true,0); gtk_box_pack_start(GTK_BOX(gain_vbox),gain_label,false,false,0); @@ -115,8 +112,6 @@ static void fill_sample_table(DrMrUi* ui, int samples) { gtk_container_add(GTK_CONTAINER(frame),hbox); - gtk_widget_size_request(frame,&req); - gtk_table_attach_defaults(ui->sample_table,frame,col,col+1,row,row+1); col++; @@ -131,50 +126,38 @@ void kit_combobox_changed(GtkComboBox* box, gpointer data) { DrMrUi* ui = (DrMrUi*)data; gint new_kit = gtk_combo_box_get_active (GTK_COMBO_BOX(box)); float fkit = (float)new_kit; - if (ui->curKit >= 0 && ui->curKit != new_kit) { - int samples = ui->kits->kits[new_kit].samples; - if (ui->sample_table) - gtk_widget_destroy(GTK_WIDGET(ui->sample_table)); - ui->sample_table = GTK_TABLE(gtk_table_new(1,1,true)); - ui->curKit = new_kit; - if (ui->gain_sliders) free(ui->gain_sliders); - if (ui->pan_sliders) free(ui->pan_sliders); - ui->gain_sliders = malloc(samples*sizeof(GtkWidget*)); - ui->pan_sliders = malloc(samples*sizeof(GtkWidget*)); - fill_sample_table(ui,samples); - gtk_box_pack_start(GTK_BOX(ui->drmr_widget),GTK_WIDGET(ui->sample_table), - true,true,5); - gtk_box_reorder_child(GTK_BOX(ui->drmr_widget),GTK_WIDGET(ui->sample_table),0); - gtk_widget_show_all(GTK_WIDGET(ui->sample_table)); + if (ui->curKit != new_kit) ui->write(ui->controller,DRMR_KITNUM,4,0,&fkit); - } } -static void fill_kit_combo(GtkComboBoxText* combo, kits* kits) { +static void fill_kit_combo(GtkComboBox* combo, kits* kits) { int i; - for (i=0;inum_kits;i++) - gtk_combo_box_text_append_text(combo,kits->kits[i].name); + GtkTreeIter iter; + GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(combo)); + for (i=0;inum_kits;i++) { + gtk_list_store_append (store, &iter); + gtk_list_store_set(store, &iter, 0, kits->kits[i].name, -1); + } } static void build_drmr_ui(DrMrUi* ui) { GtkWidget *drmr_ui_widget; - GtkWidget *sample_table; GtkWidget *kit_hbox, *kit_combo_box, *kit_label; + GtkCellRenderer *cell_rend; drmr_ui_widget = gtk_vbox_new(false,0); g_object_set(drmr_ui_widget,"border-width",6,NULL); - sample_table = gtk_table_new(1,1,true); - gtk_table_set_col_spacings(GTK_TABLE(sample_table),5); - gtk_table_set_row_spacings(GTK_TABLE(sample_table),5); - - gtk_box_pack_start(GTK_BOX(drmr_ui_widget),sample_table, - true,true,5); + ui->kit_store = gtk_list_store_new(1,G_TYPE_STRING); kit_hbox = gtk_hbox_new(false,0); - kit_combo_box = gtk_combo_box_text_new(); + kit_combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(ui->kit_store)); kit_label = gtk_label_new("Kit:"); + cell_rend = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(kit_combo_box), cell_rend, true); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(kit_combo_box), cell_rend,"text",0,NULL); + gtk_box_pack_start(GTK_BOX(kit_hbox),kit_label, false,false,15); gtk_box_pack_start(GTK_BOX(kit_hbox),kit_combo_box, @@ -183,8 +166,9 @@ static void build_drmr_ui(DrMrUi* ui) { false,false,5); ui->drmr_widget = drmr_ui_widget; - ui->sample_table = GTK_TABLE(sample_table); - ui->kit_combo = GTK_COMBO_BOX_TEXT(kit_combo_box); + ui->sample_table = NULL; + ui->kit_combo = GTK_COMBO_BOX(kit_combo_box); + g_signal_connect(G_OBJECT(kit_combo_box),"changed",G_CALLBACK(kit_combobox_changed),ui); @@ -206,10 +190,11 @@ instantiate(const LV2UI_Descriptor* descriptor, ui->controller = controller; ui->drmr_widget = NULL; ui->curKit = -1; + ui->samples = 0; *widget = NULL; build_drmr_ui(ui); - + ui->kits = scan_kits(); ui->gain_quark = g_quark_from_string("drmr_gain_quark"); ui->pan_quark = g_quark_from_string("drmr_pan_quark"); @@ -227,6 +212,8 @@ instantiate(const LV2UI_Descriptor* descriptor, static void cleanup(LV2UI_Handle handle) { DrMrUi* ui = (DrMrUi*)handle; gtk_widget_destroy(ui->drmr_widget); + if (ui->gain_sliders) free(ui->gain_sliders); + if (ui->pan_sliders) free(ui->pan_sliders); free(ui); } @@ -245,28 +232,52 @@ port_event(LV2UI_Handle handle, else { int kit = (int)(*((float*)buffer)); int samples = ui->kits->kits[kit].samples; + GtkWidget** gain_sliders; + GtkWidget** pan_sliders; + if (ui->sample_table) { + ui->gain_sliders = NULL; + ui->pan_sliders = NULL; + gtk_widget_destroy(GTK_WIDGET(ui->sample_table)); + } + ui->sample_table = GTK_TABLE(gtk_table_new(1,1,true)); + gtk_table_set_col_spacings(ui->sample_table,5); + gtk_table_set_row_spacings(ui->sample_table,5); ui->curKit = kit; - ui->gain_sliders = malloc(samples*sizeof(GtkWidget*)); - ui->pan_sliders = malloc(samples*sizeof(GtkWidget*)); - fill_sample_table(ui,samples); - gtk_combo_box_set_active (GTK_COMBO_BOX(ui->kit_combo), kit); + if (ui->gain_sliders) free(ui->gain_sliders); + if (ui->pan_sliders) free(ui->pan_sliders); + gain_sliders = malloc(samples*sizeof(GtkWidget*)); + pan_sliders = malloc(samples*sizeof(GtkWidget*)); + fill_sample_table(ui,samples,gain_sliders,pan_sliders); + gtk_box_pack_start(GTK_BOX(ui->drmr_widget),GTK_WIDGET(ui->sample_table), + true,true,5); + gtk_box_reorder_child(GTK_BOX(ui->drmr_widget),GTK_WIDGET(ui->sample_table),0); gtk_widget_show_all(GTK_WIDGET(ui->sample_table)); + gtk_combo_box_set_active(ui->kit_combo,kit); + ui->samples = samples; + ui->gain_sliders = gain_sliders; + ui->pan_sliders = pan_sliders; } } else if (index >= DRMR_GAIN_ONE && - index <= DRMR_GAIN_SIXTEEN) { + index <= DRMR_GAIN_THIRTYTWO) { if (ui->gain_sliders) { float gain = *(float*)buffer; - GtkRange* range = GTK_RANGE(ui->gain_sliders[index-DRMR_GAIN_ONE]); - gtk_range_set_value(range,gain); + int idx = index-DRMR_GAIN_ONE; + if (idx < ui->samples) { + GtkRange* range = GTK_RANGE(ui->gain_sliders[idx]); + gtk_range_set_value(range,gain); + } } } else if (index >= DRMR_PAN_ONE && - index <= DRMR_PAN_SIXTEEN) { + index <= DRMR_PAN_THIRTYTWO) { if (ui->pan_sliders) { float pan = *(float*)buffer; - GtkRange* range = GTK_RANGE(ui->pan_sliders[index-DRMR_PAN_ONE]); - gtk_range_set_value(range,pan); + int idx = index-DRMR_PAN_ONE; + if (idx < ui->samples) { + GtkRange* range = GTK_RANGE(ui->pan_sliders[idx]); + gtk_range_set_value(range,pan); + } } } }