void radix_sort(int* a,int n) { int* bucket=(int*)malloc(sizeof(int)*n); int count[radix]; for(int i=0;i<2;++i) { memset(count,0,sizeof(int)*radix); for(int j=0;j<n;++j) { count[get_part(a[j],i)]++; } for(int j=1;j<radix;++j) { count[j]+=count[j-1]; } for(int j=n-1;j>=0;--j) { int k=get_part(a[j],i); bucket[count[k]-1]=a[j]; count[k]--; } memcpy(a,bucket,sizeof(int)*n); } free(bucket); }
/* * Given a font name this function returns the part used in the second scroll list. */ static void style_part(char *font, char *buf) { char buf2[TEMP_BUF_SIZE]; char buf3[TEMP_BUF_SIZE]; get_part(font, 3, buf3); get_part(font, 5, buf2); if (!strcmp(buf2, "normal") && !strcmp(buf2, "Normal") && !strcmp(buf2, "NORMAL")) vim_snprintf(buf, TEMP_BUF_SIZE, "%s %s", buf3, buf2); else strcpy(buf, buf3); get_part(font, 6, buf2); if (buf2[0] != '\0') vim_snprintf(buf3, TEMP_BUF_SIZE, "%s %s", buf, buf2); else strcpy(buf3, buf); get_part(font, 4, buf2); if (!strcmp(buf2, "o") || !strcmp(buf2, "O")) vim_snprintf(buf, TEMP_BUF_SIZE, "%s oblique", buf3); else if (!strcmp(buf2, "i") || !strcmp(buf2, "I")) vim_snprintf(buf, TEMP_BUF_SIZE, "%s italic", buf3); if (!strcmp(buf, " ")) strcpy(buf, "-"); }
/* * Given a font name this function returns the part used in the third * scroll list. */ static void size_part(char *font, char *buf, int inPixels) { int size; float temp; *buf = '\0'; if (inPixels) { get_part(font, 7, buf); if (*buf != NUL) { size = atoi(buf); sprintf(buf, "%3d", size); } } else { get_part(font, 8, buf); if (*buf != NUL) { size = atoi(buf); temp = (float)size / 10.0; size = temp; if (buf[strlen(buf) - 1] == '0') sprintf(buf, "%3d", size); else sprintf(buf, "%4.1f", temp); } } }
/* * Given a font name this function returns the part used in the first * scroll list. */ static void name_part(char *font, char *buf) { char buf2[TEMP_BUF_SIZE]; char buf3[TEMP_BUF_SIZE]; get_part(font, 2, buf2); get_part(font, 1, buf3); if (*buf3 != NUL) vim_snprintf(buf, TEMP_BUF_SIZE, "%s (%s)", buf2, buf3); else vim_snprintf(buf, TEMP_BUF_SIZE, "%s", buf2); }
/***************************************************************************** * process_all_notes_off() * * Process all notes off for a single channel. The events for each channel * should have been queued once for each engine already. *****************************************************************************/ void process_all_notes_off(MIDI_EVENT *event, unsigned int part_num) { PART *part = get_part(part_num); VOICE *voice; unsigned int voice_num; int j; PHASEX_DEBUG(DEBUG_CLASS_MIDI_EVENT, "*** All notes off! Part %d: event_type=0x%02x\n", (part_num + 1), event->type); /* let engine shut off notes gracefully */ for (voice_num = 0; voice_num < (unsigned int) setting_polyphony; voice_num++) { voice = get_voice(part_num, voice_num); voice->keypressed = -1; } /* re-initialize this part's keylists */ part->head = NULL; part->cur = NULL; part->prev = NULL; part->midi_key = -1; part->prev_key = -1; /* re-initialize this part's keylist nodes */ for (j = 0; j < 128; j++) { part->keylist[j].midi_key = (short) j; part->keylist[j].next = NULL; } }
/* * Given a font name this function returns the part used in the choice menu. */ static void encoding_part(char *font, char *buf) { char buf1[TEMP_BUF_SIZE]; char buf2[TEMP_BUF_SIZE]; *buf = '\0'; get_part(font, 13, buf1); get_part(font, 14, buf2); if (*buf1 != NUL && *buf2 != NUL) vim_snprintf(buf, TEMP_BUF_SIZE, "%s-%s", buf1, buf2); if (!strcmp(buf, " ")) strcpy(buf, "-"); }
/***************************************************************************** * init_gui_patch() { * * Initializes the gui patch data, with parameters copied from the patch * that is marked as currently visible. Patch and param data structures * are established as well. *****************************************************************************/ void init_gui_patch(void) { PATCH *patch = get_visible_patch(); PARAM *param; PARAM *gui_param; unsigned int param_num; gp = &gui_patch; memset(gp, 0, sizeof(PATCH)); memset(&gui_dummy_patch_state, 0, sizeof(PATCH_STATE)); gp->state = &gui_dummy_patch_state; gp->name = NULL; gp->filename = NULL; gp->directory = NULL; gp->sess_num = 0; gp->part_num = 0; gp->prog_num = 0; gp->part = get_part(0); for (param_num = 0; param_num < NUM_HELP_PARAMS; param_num++) { param = & (patch->param[param_num]); gui_param = & (gp->param[param_num]); gui_param->info = get_param_info_by_id(param_num); gui_param->patch = gp; gui_param->value.cc_val = param->value.cc_val; gui_param->value.int_val = param->value.int_val; gui_param->value.cc_prev = param->info->cc_default; } }
/***************************************************************************** * init_patch_bank() *****************************************************************************/ void init_patch_bank(void) { PATCH *patch; int part_num; unsigned int prog_num; /* initialize patchbank memory */ for (part_num = 0; part_num < MAX_PARTS; part_num++) { visible_prog_num[part_num] = 0; get_part(part_num)->midi_channel = part_num; for (prog_num = 0; prog_num < PATCH_BANK_SIZE; prog_num++) { patch = & (patch_bank[part_num][prog_num]); patch->name = NULL; patch->filename = NULL; patch->directory = NULL; init_patch_data_structures(patch, SESSION_BANK_SIZE, (unsigned int) part_num, prog_num); patch->param[PARAM_MIDI_CHANNEL].value.cc_prev = part_num; patch->param[PARAM_MIDI_CHANNEL].value.cc_val = part_num; patch->param[PARAM_MIDI_CHANNEL].value.int_val = part_num + patch->param[PARAM_MIDI_CHANNEL].info->cc_offset; } patch = set_active_patch(0, (unsigned int) part_num, 0); } /* load the bank for all parts */ load_patch_bank(); }
int main(void) { int n; printf("Please input a #: "); scanf("%d", &n); get_part(n); return 0; }
static Boolean proportional(char *font) { char buf[TEMP_BUF_SIZE]; get_part(font, 11, buf); return !strcmp(buf, "p") || !strcmp(buf, "P"); }
part_t *mt_part_get_partition(char *name) { if (!strcmp(name, "PRELOADER") || !strcmp(name, "preloader")) { tempart.start_sect = 0x0; tempart.nr_sects = 0x200; tempart.part_id = 1; return &tempart; } return get_part(name); }
/***************************************************************************** * process_hold_pedal() * * Process a Hold Pedal controller message. *****************************************************************************/ void process_hold_pedal(MIDI_EVENT *event, unsigned int part_num) { PART *part = get_part(part_num); part->hold_pedal = (event->value > 64) ? 1 : 0; if (!part->hold_pedal || (part->head == NULL)) { part->midi_key = -1; } }
static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *maxsize) { if (!str2off(arg, off)) return get_part(arg, idx, off, maxsize); if (*off >= nand_info[*idx].size) { puts("Offset exceeds device limit\n"); return -1; } *maxsize = nand_info[*idx].size - *off; return 0; }
unsigned int get_message(int client, char *text, struct info *info) { unsigned int sum = 0; unsigned int parts = info->parts; unsigned int part_size = info->part_size; // XXX //size_t retransmit_size = ceil(MAX_MESSAGE_SIZE, part_size) >> 3; //char *retransmit = (char *)malloc(retransmit_size); //ret_init(retransmit, part_size); //int write_length = write(client, retransmit, retransmit_size); //if (write_length != retransmit_size) { // LOG(INFO, "Could not send retranstmit bits to client"); // // XXX Message could contain garbage //} //free(retransmit); int tries = 1; int index; int got; while (sum < parts) { got = get_part(client, text, &index, part_size); if (got > 0) { //sum += got; //ret_clear(retransmit, index); ++sum; } else if (got == 0) { LOG(DEBUG, "got 0 (try %i)", tries); sleep(1); if (tries++ == 5) break; } else { errno = -got; LOG(DEBUG, "got < 0 (%i)", errno); errno = -got; perror("didn't read"); } } return sum; }
/***************************************************************************** * process_pitchbend() *****************************************************************************/ void process_pitchbend(MIDI_EVENT *event, unsigned int part_num) { PART *part = get_part(part_num); unsigned int bend_value; bend_value = ((unsigned int)(event->lsb & 0x7F) | ((unsigned int)(event->msb & 0x7F) << 7)); PHASEX_DEBUG(DEBUG_CLASS_MIDI_EVENT, "Received pitchbend event: 2-byte value = %d (lsb=%d msb=%d)\n", bend_value, event->lsb, event->msb); part->pitch_bend_target = ((sample_t)(bend_value) - 8192) * 0.0001220703125; /* 1/8192 */ }
int mtd_arg_off(const char *arg, int *idx, loff_t *off, loff_t *size, loff_t *maxsize, int devtype, uint64_t chipsize) { if (!str2off(arg, off)) return get_part(arg, idx, off, size, maxsize, devtype); if (*off >= chipsize) { puts("Offset exceeds device limit\n"); return -1; } *maxsize = chipsize - *off; *size = *maxsize; return 0; }
/***************************************************************************** * init_midi_processor() * * initialize keylist nodes and round-robin voice selectors *****************************************************************************/ void init_midi_processor() { PART *part; unsigned int part_num; int j; /* initialize keylist nodes and round-robin voice selectors */ for (part_num = 0; part_num < MAX_PARTS; part_num++) { part = get_part(part_num); /* initialize keylist nodes */ for (j = 0; j < 128; j++) { part->keylist[j].midi_key = j & 0x7F; part->keylist[j].next = NULL; } /* initialize round robin voice indices */ vnum[part_num] = 0; /* initialize per-part midi event buffer */ init_midi_event_queue(part_num); } }
/***************************************************************************** * process_polypressure() *****************************************************************************/ void process_polypressure(MIDI_EVENT *event, unsigned int part_num) { PART *part = get_part(part_num); PATCH_STATE *state = get_active_state(part_num); VOICE *voice; int voice_num; PHASEX_DEBUG(DEBUG_CLASS_MIDI_EVENT, "Event Channel Pressure: part=%d value=%d\n", (part_num + 1), event->polypressure); part->velocity_target = (sample_t) event->polypressure * 0.01; for (voice_num = 0; voice_num < setting_polyphony; voice_num++) { voice = get_voice(part_num, voice_num); if (voice->active) { voice->velocity = event->polypressure; voice->velocity_target_linear = (sample_t) event->polypressure * 0.01; voice->velocity_target_log = velocity_gain_table[state->amp_velocity_cc][event->polypressure]; } } }
/*=====================================================================*/ GData &GData::operator ()(int i,int j ) { return get_part(i,j); }
/* * Returns pointer to an ASCII character string that contains the name of the * selected font (in X format for naming fonts); it is the users responsibility * to free the space allocated to this string. */ char_u * gui_xm_select_font(char_u *current) { static SharedFontSelData _data; Widget parent; Widget form; Widget separator; Widget sub_form; Widget size_toggle; Widget name; Widget disp_frame; Widget frame; Arg args[64]; int n; XmString str; char big_font[MAX_FONT_NAME_LEN]; SharedFontSelData *data; data = &_data; parent = vimShell; data->names = XListFonts(XtDisplay(parent), "-*-*-*-*-*-*-*-*-*-*-*-*-*-*", MAX_FONTS, &data->num); /* * Find the name of the biggest font less than the given limit * MAX_DISPLAY_SIZE used to set up the initial height of the display * widget. */ { int i; int max; int index = 0; int size; char str[128]; for (i = 0, max = 0; i < data->num; i++) { get_part(fn(data, i), 7, str); size = atoi(str); if ((size > max) && (size < MAX_DISPLAY_SIZE)) { index = i; max = size; } } strcpy(big_font, fn(data, index)); } data->old = XLoadQueryFont(XtDisplay(parent), big_font); data->old_list = gui_motif_create_fontlist(data->old); /* Set the title of the Dialog window. */ data->dialog = XmCreateDialogShell(parent, "fontSelector", NULL, 0); str = XmStringCreateLocalized(_("Vim - Font Selector")); /* Create form popup dialog widget. */ form = XtVaCreateWidget("form", xmFormWidgetClass, data->dialog, XmNdialogTitle, str, XmNautoUnmanage, False, XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL, NULL); XmStringFree(str); sub_form = XtVaCreateManagedWidget("subForm", xmFormWidgetClass, form, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 4, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 4, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 4, XmNorientation, XmVERTICAL, NULL); data->ok = XtVaCreateManagedWidget(_("OK"), xmPushButtonGadgetClass, sub_form, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 4, NULL); apply_fontlist(data->ok); data->cancel = XtVaCreateManagedWidget(_("Cancel"), xmPushButtonGadgetClass, sub_form, XmNrightAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, data->ok, XmNtopOffset, 4, XmNshowAsDefault, True, NULL); apply_fontlist(data->cancel); /* Create the separator for beauty. */ n = 0; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, sub_form); n++; XtSetArg(args[n], XmNrightOffset, 4); n++; separator = XmCreateSeparatorGadget(form, "separator", args, n); XtManageChild(separator); /* Create font name text widget and the corresponding label. */ data->name = XtVaCreateManagedWidget("fontName", xmTextWidgetClass, form, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 4, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 4, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, separator, XmNrightOffset, 4, XmNeditable, False, XmNeditMode, XmSINGLE_LINE_EDIT, XmNmaxLength, MAX_FONT_NAME_LEN, XmNcolumns, 60, NULL); str = XmStringCreateLocalized(_("Name:")); name = XtVaCreateManagedWidget("fontNameLabel", xmLabelGadgetClass, form, XmNlabelString, str, XmNuserData, data->name, XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET, XmNleftWidget, data->name, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, data->name, XmNtopOffset, 1, NULL); XmStringFree(str); apply_fontlist(name); /* create sample display label widget */ disp_frame = XtVaCreateManagedWidget("sampleFrame", xmFrameWidgetClass, form, XmNshadowType, XmSHADOW_ETCHED_IN, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 4, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, name, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, separator, XmNrightOffset, 4, XmNalignment, XmALIGNMENT_BEGINNING, NULL); data->sample = XtVaCreateManagedWidget("sampleLabel", xmLabelWidgetClass, disp_frame, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNalignment, XmALIGNMENT_BEGINNING, XmNrecomputeSize, False, XmNfontList, data->old_list, NULL); /* create toggle button */ str = XmStringCreateLocalized(_("Show size in Points")); size_toggle = XtVaCreateManagedWidget("sizeToggle", xmToggleButtonGadgetClass, form, XmNlabelString, str, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 4, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, disp_frame, XmNbottomOffset, 4, NULL); XmStringFree(str); apply_fontlist(size_toggle); XtManageChild(size_toggle); /* Encoding pulldown menu. */ data->encoding_pulldown = XmCreatePulldownMenu(form, "encodingPulldown", NULL, 0); str = XmStringCreateLocalized(_("Encoding:")); n = 0; XtSetArg(args[n], XmNsubMenuId, data->encoding_pulldown); ++n; XtSetArg(args[n], XmNlabelString, str); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNleftOffset, 4); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNbottomWidget, size_toggle); ++n; XtSetArg(args[n], XmNbottomOffset, 4); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNrightWidget, separator); ++n; XtSetArg(args[n], XmNrightOffset, 4); ++n; data->encoding_menu = XmCreateOptionMenu(form, "encodingMenu", args, n); XmStringFree(str); XmAddTabGroup(data->encoding_menu); /* * Create scroll list widgets in a separate subform used to manage the * different sizes of the lists. */ sub_form = XtVaCreateManagedWidget("subForm", xmFormWidgetClass, form, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, data->encoding_menu, XmNbottomOffset, 4, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 4, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, separator, XmNrightOffset, 4, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNorientation, XmVERTICAL, NULL); /* font list */ frame = XtVaCreateManagedWidget("frame", xmFrameWidgetClass, sub_form, XmNshadowThickness, 0, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 50, NULL); str = XmStringCreateLocalized(_("Font:")); name = XtVaCreateManagedWidget("nameListLabel", xmLabelGadgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, XmNchildVerticalAlignment, XmALIGNMENT_CENTER, XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING, XmNlabelString, str, NULL); XmStringFree(str); apply_fontlist(name); n = 0; XtSetArg(args[n], XmNvisibleItemCount, 8); ++n; XtSetArg(args[n], XmNresizable, True); ++n; XtSetArg(args[n], XmNlistSizePolicy, XmCONSTANT); ++n; XtSetArg(args[n], XmNvisualPolicy, XmVARIABLE); ++n; #ifdef LESSTIF_VERSION XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); ++n; #endif data->list[NAME] = XmCreateScrolledList(frame, "fontList", args, n); XtVaSetValues(name, XmNuserData, data->list[NAME], NULL); /* style list */ frame = XtVaCreateManagedWidget("frame", xmFrameWidgetClass, sub_form, XmNshadowThickness, 0, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 50, XmNleftOffset, 4, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 80, NULL); str = XmStringCreateLocalized(_("Style:")); name = XtVaCreateManagedWidget("styleListLabel", xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, XmNchildVerticalAlignment, XmALIGNMENT_CENTER, XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING, XmNlabelString, str, NULL); XmStringFree(str); apply_fontlist(name); n = 0; XtSetArg(args[n], XmNvisibleItemCount, 8); ++n; XtSetArg(args[n], XmNresizable, True); ++n; XtSetArg(args[n], XmNlistSizePolicy, XmCONSTANT); ++n; XtSetArg(args[n], XmNvisualPolicy, XmVARIABLE); ++n; #ifdef LESSTIF_VERSION XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); ++n; #endif data->list[STYLE] = XmCreateScrolledList(frame, "styleList", args, n); XtVaSetValues(name, XmNuserData, data->list[STYLE], NULL); /* size list */ frame = XtVaCreateManagedWidget("frame", xmFrameWidgetClass, sub_form, XmNshadowThickness, 0, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 80, XmNleftOffset, 4, XmNrightAttachment, XmATTACH_FORM, NULL); str = XmStringCreateLocalized(_("Size:")); name = XtVaCreateManagedWidget("sizeListLabel", xmLabelGadgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, XmNchildVerticalAlignment, XmALIGNMENT_CENTER, XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING, XmNlabelString, str, NULL); XmStringFree(str); apply_fontlist(name); n = 0; XtSetArg(args[n], XmNvisibleItemCount, 8); ++n; XtSetArg(args[n], XmNresizable, True); ++n; XtSetArg(args[n], XmNlistSizePolicy, XmCONSTANT); ++n; XtSetArg(args[n], XmNvisualPolicy, XmVARIABLE); ++n; #ifdef LESSTIF_VERSION XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); ++n; #endif data->list[SIZE] = XmCreateScrolledList(frame, "sizeList", args, n); XtVaSetValues(name, XmNuserData, data->list[SIZE], NULL); /* update form widgets cancel button */ XtVaSetValues(form, XmNcancelButton, data->cancel, NULL); XtAddCallback(size_toggle, XmNvalueChangedCallback, (XtCallbackProc)stoggle_callback, (XtPointer)data); XtAddCallback(data->list[NAME], XmNbrowseSelectionCallback, (XtCallbackProc)name_callback, (XtPointer)data); XtAddCallback(data->list[STYLE], XmNbrowseSelectionCallback, (XtCallbackProc)style_callback, (XtPointer)data); XtAddCallback(data->list[SIZE], XmNbrowseSelectionCallback, (XtCallbackProc)size_callback, (XtPointer)data); XtAddCallback(data->ok, XmNactivateCallback, (XtCallbackProc)ok_callback, (XtPointer)data); XtAddCallback(data->cancel, XmNactivateCallback, (XtCallbackProc)cancel_callback, (XtPointer)data); XmProcessTraversal(data->list[NAME], XmTRAVERSE_CURRENT); /* setup tabgroups */ XmAddTabGroup(data->list[NAME]); XmAddTabGroup(data->list[STYLE]); XmAddTabGroup(data->list[SIZE]); XmAddTabGroup(size_toggle); XmAddTabGroup(data->name); XmAddTabGroup(data->ok); XmAddTabGroup(data->cancel); add_cancel_action(data->dialog, (XtCallbackProc)cancel_callback, data); /* Preset selection data. */ data->exit = False; data->in_pixels= True; data->sel[ENCODING] = NULL; data->sel[NAME] = NULL; data->sel[STYLE] = NULL; data->sel[SIZE] = NULL; data->font_name = NULL; /* set up current font parameters */ if (current && current[0] != '\0') { int i; char **names; names = XListFonts(XtDisplay(form), (char *) current, 1, &i); if (i != 0) { char name[TEMP_BUF_SIZE]; char style[TEMP_BUF_SIZE]; char size[TEMP_BUF_SIZE]; char encoding[TEMP_BUF_SIZE]; char *found; found = names[0]; name_part(found, name); style_part(found, style); size_part(found, size, data->in_pixels); encoding_part(found, encoding); if (strlen(name) > 0 && strlen(style) > 0 && strlen(size) > 0 && strlen(encoding) > 0) { data->sel[NAME] = XtNewString(name); data->sel[STYLE] = XtNewString(style); data->sel[SIZE] = XtNewString(size); data->sel[ENCODING] = XtNewString(encoding); data->font_name = XtNewString(names[0]); display_sample(data); XmTextSetString(data->name, data->font_name); } else { /* We can't preset a symbolic name, which isn't a full font * description. Therefore we just behave the same way as if the * user didn't have selected anything thus far. * * Unfortunately there is no known way to expand an abbreviated * font name. */ data->font_name = NULL; } } XFreeFontNames(names); } fill_lists(NONE, data); /* Unfortunately LessTif doesn't align the list widget's properly. I don't * have currently any idea how to fix this problem. */ XtManageChild(data->list[NAME]); XtManageChild(data->list[STYLE]); XtManageChild(data->list[SIZE]); XtManageChild(data->encoding_menu); manage_centered(form); /* modal event loop */ while (!data->exit) XtAppProcessEvent(XtWidgetToApplicationContext(data->dialog), (XtInputMask)XtIMAll); XtDestroyWidget(data->dialog); if (data->old) { XFreeFont(XtDisplay(data->dialog), data->old); XmFontListFree(data->old_list); } gui_motif_synch_fonts(); return (char_u *) data->font_name; }
int nametodisk(int *disk, long *offset, long *length) { int err, fstype, subdisk; struct part_desc pl[16]; char env[80], *envp, *pos1, *pos2, *cp; /* Decode E2CWD environment */ envp=getenv("E2CWD"); if (!envp) return E2E_NOCWD; strcpy(env,envp); /* We are going to modify it, so we make a copy */ pos1=strchr(env,':'); if (!pos1) return E2E_BADCWD; pos2=strchr(pos1+1,':'); *pos1 = 0; pos1++; for (cp=env; *cp; cp++) if (!isdigit(*cp)) return E2E_BADCWD; *disk = atoi(env); if (pos2) { *pos2 = 0; pos2++; } for (cp=pos1; *cp; cp++) if (!isdigit(*cp)) return E2E_BADCWD; subdisk = atoi(pos1)-1; if (pos2) { for (cp=pos2; *cp; cp++) if (!isdigit(*cp)) return E2E_BADCWD; cwdino = atoi(pos2); } else cwdino = EXT2_ROOT_INO; /* Check that disk contains an ext2 file system */ if (!(*disk & 0x80)) { /* Floppy disk */ *offset = 0; *length = 1440*2; /* TBD */ fstype=getfstype(*disk, 0, 0); if (fstype<0) return -fstype; if (fstype!=EXT2FS) return E2E_BADFS; return 0; } err=get_part(*disk, pl); if (err) return err; if (pl[subdisk].is_extended) return E2E_BADFS; fstype=getfstype(*disk, pl[subdisk].parttype, pl[subdisk].start); if (fstype<0) return -fstype; if (fstype!=EXT2FS) return E2E_BADFS; *offset = pl[subdisk].start; *length = pl[subdisk].length; return 0; }
int mmc_get_dl_info(void) { struct dl_status download_info; u64 dl_addr; u8 *dl_buf; part_dev_t *dev; part_t *part; int i, err, loglevel; dev = mt_part_get_device(); if (!dev) { dprintf(CRITICAL, "[DL_INFO]fail to get device\n"); err = -ENODEV; goto out; } part = get_part("flashinfo"); if (!part) { dprintf(CRITICAL, "[DL_INFO]fail to find partition flashinfo\n"); err = -ENODEV; goto out; } dl_addr = (u64)(part->start_sect + part->nr_sects) * 512ULL - DL_INFO_SIZE; dprintf(ALWAYS, "[DL_INFO]get dl info from 0x%llx\n", dl_addr); dl_buf = (u8 *)calloc(1, DL_INFO_SIZE); if (!dl_buf) { dprintf(CRITICAL, "[DL_INFO]fail to calloc buffer(count=%d)\n", DL_INFO_SIZE); err = -ENOMEM; goto fail_malloc; } err = dev->read(dev, dl_addr, dl_buf, DL_INFO_SIZE, part->part_id); if (err != DL_INFO_SIZE) { dprintf(CRITICAL, "[DL_INFO]fail to read data(%d)\n", err); err = -EIO; goto fail_read; } memcpy(&download_info, dl_buf, sizeof(download_info)); if (memcmp(download_info.magic_num, "DOWNLOAD INFORMATION!!", 22)) { dprintf(CRITICAL, "[DL_INFO]fail to find DL INFO magic\n"); err = DL_NOT_FOUND; goto fail_read; } if (!memcmp(download_info.download_status, "DL_DONE", 7) || !memcmp(download_info.download_status, "DL_CK_DONE", 10)) { loglevel = INFO; loglevel = CRITICAL; err = DL_PASS; } else { loglevel = CRITICAL; err = DL_FAIL; } dprintf(loglevel, "[DL_INFO]version: %s\n", download_info.version); dprintf(loglevel, "[DL_INFO]dl_status: %s\n", download_info.download_status); dprintf(loglevel, "[DL_INFO]dram_checksum: %s\n", download_info.ram_checksum); for (i = 0; i < PART_MAX_COUNT; i++) { if (download_info.cs_info[i].image_index != 0) { dprintf(loglevel, "[DL_INFO]image:[%02d]%-12s, checksum: %s\n", download_info.cs_info[i].image_index, download_info.img_info[i].image_name, download_info.cs_info[i].checksum_status); } } fail_read: free(dl_buf); fail_malloc: //put_part(part); out: return err; }
/***************************************************************************** * process_phase_sync() * * Process a phase sync internal MIDI message. Currently used for syncing * JACK Transport, this function performs phase correction for a given voice. *****************************************************************************/ void process_phase_sync(MIDI_EVENT *event, unsigned int part_num) { PART *part = get_part(part_num); PATCH_STATE *state = get_active_state(part_num); DELAY *delay = get_delay(part_num); CHORUS *chorus = get_chorus(part_num); VOICE *voice; int voice_num; int osc; int lfo; int phase_correction = event->value; sample_t f_phase_correction = (sample_t) phase_correction; sample_t tmp_1; delay->write_index += phase_correction; while (delay->write_index < 0.0) { delay->write_index += delay->bufsize; } while (delay->write_index >= delay->bufsize) { delay->write_index -= delay->bufsize; } chorus->lfo_index_a += f_phase_correction * chorus->lfo_adjust; while (chorus->lfo_index_a < 0.0) { chorus->lfo_index_a += F_WAVEFORM_SIZE; } while (chorus->lfo_index_a >= F_WAVEFORM_SIZE) { chorus->lfo_index_a -= F_WAVEFORM_SIZE; } chorus->lfo_index_b = chorus->lfo_index_a + (F_WAVEFORM_SIZE * 0.25); while (chorus->lfo_index_b < 0.0) { chorus->lfo_index_b += F_WAVEFORM_SIZE; } while (chorus->lfo_index_b >= F_WAVEFORM_SIZE) { chorus->lfo_index_b -= F_WAVEFORM_SIZE; } chorus->lfo_index_c = chorus->lfo_index_a + (F_WAVEFORM_SIZE * 0.5); while (chorus->lfo_index_c < 0.0) { chorus->lfo_index_c += F_WAVEFORM_SIZE; } while (chorus->lfo_index_c >= F_WAVEFORM_SIZE) { chorus->lfo_index_c -= F_WAVEFORM_SIZE; } chorus->lfo_index_d = chorus->lfo_index_a + (F_WAVEFORM_SIZE * 0.75); while (chorus->lfo_index_d < 0.0) { chorus->lfo_index_d += F_WAVEFORM_SIZE; } while (chorus->lfo_index_d >= F_WAVEFORM_SIZE) { chorus->lfo_index_d -= F_WAVEFORM_SIZE; } for (voice_num = 0; voice_num < setting_polyphony; voice_num++) { voice = get_voice(part_num, voice_num); for (osc = 0; osc < NUM_OSCS; osc++) { if (state->osc_freq_base[osc] >= FREQ_BASE_TEMPO) { switch (state->freq_mod_type[osc]) { case MOD_TYPE_LFO: tmp_1 = part->lfo_out[state->freq_lfo[osc]]; break; case MOD_TYPE_OSC: tmp_1 = (voice->osc_out1[part->osc_freq_mod[osc]] + voice->osc_out2[part->osc_freq_mod[osc]]) * 0.5; break; case MOD_TYPE_VELOCITY: tmp_1 = voice->velocity_coef_linear; break; default: tmp_1 = 0.0; break; } voice->index[osc] += f_phase_correction * halfsteps_to_freq_mult((tmp_1 * state->freq_lfo_amount[osc]) + part->osc_pitch_bend[osc] + state->osc_transpose[osc] + state->voice_osc_tune[voice->id] ) * voice->osc_freq[osc] * wave_period; while (voice->index[osc] < 0.0) { voice->index[osc] += F_WAVEFORM_SIZE; } while (voice->index[osc] >= F_WAVEFORM_SIZE) { voice->index[osc] -= F_WAVEFORM_SIZE; } } } } for (lfo = 0; lfo < NUM_LFOS; lfo++) { if (state->lfo_freq_base[lfo] >= FREQ_BASE_TEMPO) { part->lfo_index[lfo] += f_phase_correction * part->lfo_freq[lfo] * halfsteps_to_freq_mult(state->lfo_transpose[lfo] + part->lfo_pitch_bend[lfo]) * wave_period; while (part->lfo_index[lfo] < 0.0) { part->lfo_index[lfo] += F_WAVEFORM_SIZE; } while (part->lfo_index[lfo] >= F_WAVEFORM_SIZE) { part->lfo_index[lfo] -= F_WAVEFORM_SIZE; } } } }
/***************************************************************************** * process_bpm_change() * * Process a BPM change pseudo MIDI message. Currently used when syncing * JACK Transport, this adjust BPM, independent of controller assignment. * * TODO: Rework _all_ phasex BPM code, since this is almost identical to * update_bpm() in bpm.c. *****************************************************************************/ void process_bpm_change(MIDI_EVENT *event, unsigned int part_num) { PART *part = get_part(part_num); PATCH_STATE *state = get_active_state(part_num); PARAM *param = get_param(part_num, PARAM_BPM); DELAY *delay = get_delay(part_num); CHORUS *chorus = get_chorus(part_num); VOICE *voice; int int_val = (int)(event->float_value); int cc_val = int_val - 64; int voice_num; int lfo; int osc; PHASEX_DEBUG(DEBUG_CLASS_MIDI_TIMING, "+++ Processing BPM change. New BPM = %lf +++\n", event->float_value); param->value.cc_val = cc_val; param->value.int_val = int_val; /* For now, this is handled much like the normal param callback for BPM, execpt that here we use floating point values instead of integer. */ global.bpm = event->float_value; global.bps = event->float_value / 60.0; if (param->value.cc_val != cc_val) { param->value.cc_prev = param->value.cc_val; param->value.cc_val = cc_val; param->value.int_val = int_val; param->updated = 1; } /* initialize all variables based on bpm */ state->bpm = event->float_value; state->bpm_cc = (short)(param->value.cc_val & 0x7F); /* re-initialize delay size */ delay->size = state->delay_time * f_sample_rate / global.bps; delay->length = (int)(delay->size); /* re-initialize chorus lfos */ chorus->lfo_freq = global.bps * state->chorus_lfo_rate; chorus->lfo_adjust = chorus->lfo_freq * wave_period; chorus->phase_freq = global.bps * state->chorus_phase_rate; chorus->phase_adjust = chorus->phase_freq * wave_period; /* per-lfo setup */ for (lfo = 0; lfo < NUM_LFOS; lfo++) { /* re-calculate frequency and corresponding index adjustment */ if (state->lfo_freq_base[lfo] >= FREQ_BASE_TEMPO) { part->lfo_freq[lfo] = global.bps * state->lfo_rate[lfo]; part->lfo_adjust[lfo] = part->lfo_freq[lfo] * wave_period; } } /* per-oscillator setup */ for (osc = 0; osc < NUM_OSCS; osc++) { /* re-calculate tempo based osc freq */ if (state->osc_freq_base[osc] >= FREQ_BASE_TEMPO) { for (voice_num = 0; voice_num < setting_polyphony; voice_num++) { voice = get_voice(part_num, voice_num); voice->osc_freq[osc] = global.bps * state->osc_rate[osc]; } } } }
/***************************************************************************** * process_note_off() * * Process a single note-off event (either a note-off message, or a note-on * message with velocity set to zero). Select a voices to be turned on/off, * remove key from list, and call process_keytrigger() for any portamento, * envelope, osc and lfo init-phase, and filter-follow triggering actions for * note-off events that cause new notes to be triggered (mono modes). *****************************************************************************/ void process_note_off(MIDI_EVENT *event, unsigned int part_num) { VOICE *voice; VOICE *old_voice = NULL; VOICE *loop_voice; PART *part = get_part(part_num); PATCH_STATE *state = get_active_state(part_num); int keytrigger = 0; int free_voice = -1; int voice_num; int unlink; int voice_count = 0; switch (state->keymode) { case KEYMODE_POLY: /* find voice mapped to note being shut off */ vnum[part_num] = -1; for (voice_num = 0; voice_num < setting_polyphony; voice_num++) { loop_voice = get_voice(part_num, voice_num); if (loop_voice->midi_key == event->note) { loop_voice->keypressed = -1; vnum[part_num] = voice_num; } } if (vnum[part_num] == -1) { vnum[part_num] = 0; keytrigger = 0; } break; case KEYMODE_MONO_SMOOTH: /* find voice mapped to note being shut off, if any */ keytrigger = 0; for (voice_num = 0; voice_num < setting_polyphony; voice_num++) { loop_voice = get_voice(part_num, voice_num); if (loop_voice->keypressed == event->note) { loop_voice->keypressed = -1; if (event->note == part->midi_key) { old_voice = loop_voice; } } } break; case KEYMODE_MONO_RETRIGGER: /* find voice mapped to note being shut off, if any */ keytrigger = 0; for (voice_num = 0; voice_num < setting_polyphony; voice_num++) { loop_voice = get_voice(part_num, ((voice_num + vnum[part_num] + 1) % setting_polyphony)); if (loop_voice->allocated == 0) { free_voice = loop_voice->id; } else if (loop_voice->midi_key == event->note) { loop_voice->keypressed = -1; vnum[part_num] = (voice_num + 1) % setting_polyphony; if (event->note == part->midi_key) { old_voice = loop_voice; } } } if ((old_voice != NULL) && (free_voice > -1)) { vnum[part_num] = free_voice; } break; case KEYMODE_MONO_UNISON_4: voice_count = 4; vnum[part_num] = 0; if (part->midi_key == event->note) { keytrigger = 1; old_voice = get_voice(part_num, vnum[part_num]); } break; case KEYMODE_MONO_UNISON_6: voice_count = 6; vnum[part_num] = 0; if (part->midi_key == event->note) { keytrigger = 1; old_voice = get_voice(part_num, vnum[part_num]); } break; case KEYMODE_MONO_UNISON_8: voice_count = 8; vnum[part_num] = 0; if (part->midi_key == event->note) { keytrigger = 1; old_voice = get_voice(part_num, vnum[part_num]); } break; case KEYMODE_MONO_MULTIKEY: /* mono multikey needs keytrigger activities on note off for resetting oscillator frequencies. */ vnum[part_num] = 0; if (part->midi_key == event->note) { keytrigger = 1; old_voice = get_voice(part_num, vnum[part_num]); } break; } part->prev_key = part->midi_key; part->midi_key = event->note; PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "voice %2d: Event Note Off: part=%d " "voice=%2d note=%3d velocity=%3d keylist=:", (vnum[part_num] + 1), (part_num + 1), (vnum[part_num] + 1), event->note, event->velocity); /* remove this key from the list and then find the last key */ part->prev = NULL; part->cur = part->head; unlink = 0; while (part->cur != NULL) { /* if note is found, unlink it from the list */ if (part->cur->midi_key == event->note) { PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "-%d-:", part->cur->midi_key); unlink = 1; if (part->prev != NULL) { part->prev->next = part->cur->next; part->cur->next = NULL; part->cur = part->prev->next; } else { part->head = part->cur->next; part->cur->next = NULL; part->cur = part->head; } } /* otherwise, on to the next key in the list */ else { PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "%d:", part->cur->midi_key); part->prev = part->cur; part->cur = part->cur->next; } } PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "\n"); PHASEX_DEBUG(DEBUG_CLASS_MIDI_TIMING, DEBUG_COLOR_BLUE "------- %d ------- " DEBUG_COLOR_DEFAULT, event->note); if (!unlink) { /* Received note-off w/o corresponding note-on. */ PHASEX_DEBUG(DEBUG_CLASS_MIDI_TIMING, DEBUG_COLOR_RED "----------- " DEBUG_COLOR_DEFAULT); } /* keep pointer to current voice around */ voice = get_voice(part_num, vnum[part_num]); /* ignore the note in the note off message if found in list */ if ((part->prev != NULL) && (part->prev->midi_key == event->note)) { part->cur = part->head; while (part->cur != NULL) { if (part->cur->midi_key != event->note) { part->prev = part->cur; } part->cur = part->cur->next; } } /* check for keys left on the list */ if (part->prev != NULL) { /* set last and current keys in play respective of notes still held */ part->last_key = part->prev->midi_key; part->midi_key = part->prev->midi_key; part->prev->next = NULL; /* Retrigger and smooth modes need voice allocation with keys still on list multikey always need osc remapping until all keys are done. */ switch (state->keymode) { case KEYMODE_MONO_RETRIGGER: if (old_voice == NULL) { keytrigger--; break; } old_voice->cur_amp_interval = ENV_INTERVAL_RELEASE; old_voice->cur_amp_sample = -1; /* intentional fall-through */ case KEYMODE_MONO_SMOOTH: voice->midi_key = part->midi_key; voice->keypressed = part->midi_key; /* use previous velocity for this generated note event */ voice->velocity = part->velocity; voice->velocity_target_linear = voice->velocity_coef_linear = part->velocity_target = part->velocity_coef = ((sample_t) part->velocity) * 0.01; voice->velocity_target_log = voice->velocity_coef_log = velocity_gain_table[state->amp_velocity_cc][part->velocity]; /* intentional fall-through */ case KEYMODE_MONO_UNISON_4: case KEYMODE_MONO_UNISON_6: case KEYMODE_MONO_UNISON_8: case KEYMODE_MONO_MULTIKEY: keytrigger++; break; } } /* re-init list if no keys */ else { voice->midi_key = -1; voice->keypressed = -1; for (voice_num = 0; voice_num < voice_count; voice_num++) { if ( vnum[part_num] == voice_num ) continue; loop_voice = get_voice(part_num, voice_num); loop_voice->midi_key = -1; loop_voice->keypressed = -1; } part->head = NULL; if (!part->hold_pedal) { part->midi_key = -1; } } if (keytrigger > 0) { process_keytrigger(event, old_voice, voice, part_num); for (voice_num = 0; voice_num < voice_count; voice_num++) { if ( vnum[part_num] == voice_num ) continue; loop_voice = get_voice(part_num, voice_num); process_keytrigger(event, old_voice, loop_voice, part_num); } } }
int main(int argc, char **argv) { unsigned int start; int bytes_count = 0; char filename[256]; memset(filename, 0, sizeof(filename)); // Parsing command line char c; action_t action = NONE; bool start_addr_specified = false, pgm_specified = false, part_specified = false, bytes_count_specified = false; memtype_t memtype = FLASH; int i; programmer_t *pgm = NULL; const stm8_device_t *part = NULL; while((c = getopt (argc, argv, "r:w:v:nc:p:s:b:luV")) != (char)-1) { switch(c) { case 'c': pgm_specified = true; for(i = 0; pgms[i].name; i++) { if(!strcmp(optarg, pgms[i].name)) pgm = &pgms[i]; } break; case 'p': part_specified = true; part = get_part(optarg); break; case 'l': for(i = 0; stm8_devices[i].name; i++) printf("%s ", stm8_devices[i].name); printf("\n"); exit(0); case 'r': action = READ; strcpy(filename, optarg); break; case 'w': action = WRITE; strcpy(filename, optarg); break; case 'v': action = VERIFY; strcpy(filename, optarg); break; case 'u': action = UNLOCK; start = 0x4800; memtype = OPT; strcpy(filename, "Workaround"); break; case 's': // Start addr is depending on MCU type if(strcasecmp(optarg, "flash") == 0) { memtype = FLASH; } else if(strcasecmp(optarg, "eeprom") == 0) { memtype = EEPROM; } else if(strcasecmp(optarg, "ram") == 0) { memtype = RAM; } else if(strcasecmp(optarg, "opt") == 0) { memtype = OPT; } else { // Start addr is specified explicitely memtype = UNKNOWN; int success = sscanf(optarg, "%x", &start); assert(success); start_addr_specified = true; } break; case 'b': bytes_count = atoi(optarg); bytes_count_specified = true; break; case 'V': print_version_and_exit( (bool)0); break; case '?': print_help_and_exit(argv[0], false); default: print_help_and_exit(argv[0], true); } } if(argc <= 1) print_help_and_exit(argv[0], true); if(pgm_specified && !pgm) { fprintf(stderr, "No valid programmer specified. Possible values are:\n"); dump_pgms( (programmer_t *) &pgms); exit(-1); } if(!pgm) spawn_error("No programmer has been specified"); if(part_specified && !part) { fprintf(stderr, "No valid part specified. Use -l to see the list of supported devices.\n"); exit(-1); } if(!part) spawn_error("No part has been specified"); // Try define memory type by address if(memtype == UNKNOWN) { if((start >= 0x4800) && (start < 0x4880)) { memtype = OPT; } if((start >= part->ram_start) && (start < part->ram_start + part->ram_size)) { memtype = RAM; } else if((start >= part->flash_start) && (start < part->flash_start + part->flash_size)) { memtype = FLASH; } else if((start >= part->eeprom_start) && (start < part->eeprom_start + part->eeprom_size)) { memtype = EEPROM; } } if(memtype != UNKNOWN) { // Selecting start addr depending on // specified part and memtype switch(memtype) { case RAM: if(!start_addr_specified) { start = part->ram_start; } if(!bytes_count_specified || bytes_count > part->ram_size) { bytes_count = part->ram_size; } fprintf(stderr, "Determine RAM area\r\n"); break; case EEPROM: if(!start_addr_specified) { start = part->eeprom_start; } if(!bytes_count_specified || bytes_count > part->eeprom_size) { bytes_count = part->eeprom_size; } fprintf(stderr, "Determine EEPROM area\r\n"); break; case FLASH: if(!start_addr_specified) { start = part->flash_start; } if(!bytes_count_specified || bytes_count > part->flash_size) { bytes_count = part->flash_size; } fprintf(stderr, "Determine FLASH area\r\n"); break; case OPT: if(!start_addr_specified) { start = 0x4800; } size_t opt_size = (part->flash_size <= 8*1024 ? 0x40 : 0x80); if(!bytes_count_specified || bytes_count > opt_size) { bytes_count = opt_size; } fprintf(stderr, "Determine OPT area\r\n"); break; } start_addr_specified = true; } if(!action) spawn_error("No action has been specified"); if(!start_addr_specified) spawn_error("No memtype or start_addr has been specified"); if (!strlen(filename)) spawn_error("No filename has been specified"); if(!action || !start_addr_specified || !strlen(filename)) print_help_and_exit(argv[0], true); if(!usb_init(pgm, pgm->usb_vid, pgm->usb_pid)) spawn_error("Couldn't initialize stlink"); if(!pgm->open(pgm)) spawn_error("Error communicating with MCU. Please check your SWIM connection."); FILE *f; if(action == READ) { fprintf(stderr, "Reading %d bytes at 0x%x... ", bytes_count, start); fflush(stderr); int bytes_count_align = ((bytes_count-1)/256+1)*256; // Reading should be done in blocks of 256 bytes unsigned char *buf = malloc(bytes_count_align); if(!buf) spawn_error("malloc failed"); int recv = pgm->read_range(pgm, part, buf, start, bytes_count_align); if(recv < bytes_count_align) { fprintf(stderr, "\r\nRequested %d bytes but received only %d.\r\n", bytes_count_align, recv); spawn_error("Failed to read MCU"); } if(!(f = fopen(filename, "w"))) spawn_error("Failed to open file"); if(is_ext(filename, ".ihx") || is_ext(filename, ".hex")) { fprintf(stderr, "Reading from Intel hex file "); ihex_write(f, buf, start, start+bytes_count); } else if(is_ext(filename, ".s19") || is_ext(filename, ".s8") || is_ext(filename, ".srec")) { printf("Reading from Motorola S-record files are not implemented (yet)\n"); printf("Exiting...\n"); exit(-1); //TODO Remove the above message and exit, and implement reading from S-record. fprintf(stderr, "Reading from Motorola S-record file "); srec_write(f, buf, start, start+bytes_count); } else { fwrite(buf, 1, bytes_count, f); } fclose(f); fprintf(stderr, "OK\n"); fprintf(stderr, "Bytes received: %d\n", bytes_count); } else if (action == VERIFY) { fprintf(stderr, "Verifing %d bytes at 0x%x... ", bytes_count, start); fflush(stderr); int bytes_count_align = ((bytes_count-1)/256+1)*256; // Reading should be done in blocks of 256 bytes unsigned char *buf = malloc(bytes_count_align); if(!buf) spawn_error("malloc failed"); int recv = pgm->read_range(pgm, part, buf, start, bytes_count_align); if(recv < bytes_count_align) { fprintf(stderr, "\r\nRequested %d bytes but received only %d.\r\n", bytes_count_align, recv); spawn_error("Failed to read MCU"); } if(!(f = fopen(filename, "r"))) spawn_error("Failed to open file"); unsigned char *buf2 = malloc(bytes_count); if(!buf2) spawn_error("malloc failed"); int bytes_to_verify; /* reading bytes to RAM */ if(is_ext(filename, ".ihx") || is_ext(filename, ".hex")) { bytes_to_verify = ihex_read(f, buf, start, start + bytes_count); } else { fseek(f, 0L, SEEK_END); bytes_to_verify = ftell(f); if(bytes_count_specified) { bytes_to_verify = bytes_count; } else if(bytes_count < bytes_to_verify) { bytes_to_verify = bytes_count; } fseek(f, 0, SEEK_SET); fread(buf2, 1, bytes_to_verify, f); } fclose(f); if(memcmp(buf, buf2, bytes_to_verify) == 0) { fprintf(stderr, "OK\n"); fprintf(stderr, "Bytes verified: %d\n", bytes_to_verify); } else { fprintf(stderr, "FAILED\n"); exit(-1); } } else if (action == WRITE) { if(!(f = fopen(filename, "r"))) spawn_error("Failed to open file"); int bytes_count_align = ((bytes_count-1)/part->flash_block_size+1)*part->flash_block_size; unsigned char *buf = malloc(bytes_count_align); if(!buf) spawn_error("malloc failed"); memset(buf, 0, bytes_count_align); // Clean aligned buffer int bytes_to_write; /* reading bytes to RAM */ if(is_ext(filename, ".ihx") || is_ext(filename, ".hex")) { fprintf(stderr, "Writing Intel hex file "); bytes_to_write = ihex_read(f, buf, start, start + bytes_count); } else if (is_ext(filename, ".s19") || is_ext(filename, ".s8") || is_ext(filename, ".srec")) { fprintf(stderr, "Writing Motorola S-record file "); bytes_to_write = srec_read(f, buf, start, start + bytes_count); } else { fprintf(stderr, "Writing binary file "); fseek(f, 0L, SEEK_END); bytes_to_write = ftell(f); if(bytes_count_specified) { bytes_to_write = bytes_count; } else if(bytes_count < bytes_to_write) { bytes_to_write = bytes_count; } fseek(f, 0, SEEK_SET); fread(buf, 1, bytes_to_write, f); } fprintf(stderr, "%d bytes at 0x%x... ", bytes_to_write, start); /* flashing MCU */ int sent = pgm->write_range(pgm, part, buf, start, bytes_to_write, memtype); if(pgm->reset) { // Restarting core (if applicable) pgm->reset(pgm); } fprintf(stderr, "OK\n"); fprintf(stderr, "Bytes written: %d\n", sent); fclose(f); } else if (action == UNLOCK) { int bytes_to_write=part->option_bytes_size; if (part->read_out_protection_mode==ROP_UNKNOWN) spawn_error("No unlocking mode defined for this device. You may need to edit the file stm8.c"); unsigned char *buf=malloc(bytes_to_write); if(!buf) spawn_error("malloc failed"); if (part->read_out_protection_mode==ROP_STM8S_STD) { for (int i=0; i<bytes_to_write;i++) { buf[i]=0; if ((i>0)&&((i&1)==0)) buf[i]=0xff; } } /* flashing MCU */ int sent = pgm->write_range(pgm, part, buf, start, bytes_to_write, memtype); if(pgm->reset) { // Restarting core (if applicable) pgm->reset(pgm); } fprintf(stderr, "Unlocked device. Option bytes reset to default state.\n"); fprintf(stderr, "Bytes written: %d\n", sent); } return(0); }
/***************************************************************************** * process_keytrigger() * * Process voice/patch/param updates for keytrigger events. This function * contains most of the logic for activating voices, and should be broken up * into its logical components. *****************************************************************************/ void process_keytrigger(MIDI_EVENT *UNUSED(event), VOICE *old_voice, VOICE *voice, unsigned int part_num) { VOICE *loop_voice; PART *part = get_part(part_num); PATCH_STATE *state = get_active_state(part_num); int osc; int lfo; int voice_num; int staccato = 1; int env_trigger = 0; sample_t tmp; PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "voice %2d: process_keytrigger(): old_voice=%2d voice=%2d\n", (voice->id + 1), (old_voice == NULL ? 0 : (old_voice->id + 1)), (voice->id + 1)); /* check for notes currently in play */ switch (state->keymode) { case KEYMODE_MONO_RETRIGGER: env_trigger = 1; /* intentional fall-through */ case KEYMODE_MONO_UNISON_4: case KEYMODE_MONO_UNISON_6: case KEYMODE_MONO_UNISON_8: case KEYMODE_MONO_MULTIKEY: case KEYMODE_MONO_SMOOTH: if (voice->cur_amp_interval >= ENV_INTERVAL_RELEASE) { staccato = 1; env_trigger = 1; } else { staccato = 0; } break; case KEYMODE_POLY: staccato = 1; for (voice_num = 0; voice_num < setting_polyphony; voice_num++) { loop_voice = get_voice(part_num, voice_num); if (loop_voice->cur_amp_interval < ENV_INTERVAL_RELEASE) { staccato = 0; break; } } env_trigger = 1; break; } /* staccato, mono retrig, and poly get new envelopes and initphases */ if (env_trigger) { /* start new amp and filter envelopes */ voice->cur_amp_interval = ENV_INTERVAL_ATTACK; voice->cur_filter_interval = ENV_INTERVAL_ATTACK; voice->cur_amp_sample = voice->amp_env_dur[ENV_INTERVAL_ATTACK] = env_interval_dur[ENV_INTERVAL_ATTACK][state->amp_attack]; voice->cur_filter_sample = voice->filter_env_dur[ENV_INTERVAL_ATTACK] = env_interval_dur[ENV_INTERVAL_ATTACK][state->filter_attack]; /* TODO: test with hold pedal. */ /* without hold pedal: */ /* voice->amp_env_delta[ENV_INTERVAL_ATTACK] = */ /* (1.0 - voice->amp_env_raw) / */ /* (sample_t)voice->amp_env_dur[ENV_INTERVAL_ATTACK]; */ /* voice->filter_env_delta[ENV_INTERVAL_ATTACK] = */ /* (1.0 - voice->filter_env_raw) / */ /* (sample_t)voice->filter_env_dur[ENV_INTERVAL_ATTACK]; */ /* with hold pedal: everything until next comment. */ voice->amp_env_raw = 0.0; voice->filter_env_raw = 0.0; if (state->amp_attack || state->amp_decay) { voice->amp_env_delta[ENV_INTERVAL_ATTACK] = (1.0 - voice->amp_env_raw) / (sample_t) voice->amp_env_dur[ENV_INTERVAL_ATTACK]; } else { voice->amp_env_delta[ENV_INTERVAL_ATTACK] = (state->amp_sustain - voice->amp_env_raw) / (sample_t) voice->amp_env_dur[ENV_INTERVAL_ATTACK]; } if (state->filter_attack || state->filter_decay) { voice->filter_env_delta[ENV_INTERVAL_ATTACK] = (1.0 - voice->filter_env_raw) / (sample_t) voice->filter_env_dur[ENV_INTERVAL_ATTACK]; } else { voice->filter_env_delta[ENV_INTERVAL_ATTACK] = (state->filter_sustain - voice->filter_env_raw) / (sample_t) voice->filter_env_dur[ENV_INTERVAL_ATTACK]; } /* end of hold pedal code changes */ /* everything except mono multikey gets new init phases. */ if (state->keymode != KEYMODE_MONO_MULTIKEY) { /* init phase for keytrig oscs */ for (osc = 0; osc < NUM_OSCS; osc++) { /* init phase (unshifted by lfo) at note start */ if ((state->osc_freq_base[osc] == FREQ_BASE_TEMPO_KEYTRIG) || (state->osc_freq_base[osc] == FREQ_BASE_MIDI_KEY)) { voice->index[osc] = part->osc_init_index[osc]; } } } /* init phase for keytrig lfos if needed */ /* TODO: determine if including env retrigger is appropriate here */ //if ((staccato) || (env_trigger)) { if (staccato) { for (lfo = 0; lfo < NUM_LFOS; lfo++) { switch (state->lfo_freq_base[lfo]) { case FREQ_BASE_MIDI_KEY: case FREQ_BASE_TEMPO_KEYTRIG: part->lfo_index[lfo] = part->lfo_init_index[lfo]; /* intentional fallthrough */ case FREQ_BASE_TEMPO: part->lfo_adjust[lfo] = part->lfo_freq[lfo] * wave_period; break; } } } } /* Both high key and low key are set to the last key and adjusted later if necessary */ part->high_key = part->low_key = part->last_key; /* set highest and lowest keys in play for things that need keyfollow */ part->cur = part->head; while (part->cur != NULL) { if (part->cur->midi_key < part->low_key) { part->low_key = part->cur->midi_key; } if (part->cur->midi_key > part->high_key) { part->high_key = part->cur->midi_key; } part->cur = part->cur->next; } /* volume keyfollow is set by last key for poly */ if (state->keymode == KEYMODE_POLY) { voice->vol_key = part->last_key; } /* volume keyfollow is set by high key for mono */ else { voice->vol_key = part->high_key; } /* set filter keyfollow key based on keyfollow mode */ switch (state->filter_keyfollow) { case KEYFOLLOW_LAST: tmp = (sample_t)(part->last_key + state->transpose - 64); for (voice_num = 0; voice_num < setting_polyphony; voice_num++) { loop_voice = get_voice(part_num, voice_num); loop_voice->filter_key_adj = tmp; } break; case KEYFOLLOW_HIGH: tmp = (sample_t)(part->high_key + state->transpose - 64); for (voice_num = 0; voice_num < setting_polyphony; voice_num++) { loop_voice = get_voice(part_num, voice_num); loop_voice->filter_key_adj = tmp; } break; case KEYFOLLOW_LOW: tmp = (sample_t)(part->low_key + state->transpose - 64); for (voice_num = 0; voice_num < setting_polyphony; voice_num++) { loop_voice = get_voice(part_num, voice_num); loop_voice->filter_key_adj = tmp; } break; case KEYFOLLOW_MIDI: voice->filter_key_adj = (sample_t)(part->last_key + state->transpose - 64); break; case KEYFOLLOW_NONE: voice->filter_key_adj = 0.0; break; } /* start at beginning of list of keys in play */ part->cur = part->head; /* Keytrigger volume only applicable to midi key based oscs portamento applicable to midi key based oscs _and_ lfos. */ /* handle per-osc portamento for the different keymodes */ for (osc = 0; osc < NUM_OSCS; osc++) { /* portamento for midi key based main osc */ if (state->osc_freq_base[osc] == FREQ_BASE_MIDI_KEY) { /* decide which key in play to assign to this oscillator */ switch (state->keymode) { case KEYMODE_MONO_MULTIKEY: /* use notes in order in oscillators */ if (part->cur != NULL) { voice->osc_key[osc] = part->cur->midi_key; if (part->cur->next != NULL) { part->cur = part->cur->next; } else { part->cur = part->head; } } else { voice->osc_key[osc] = part->last_key; } break; case KEYMODE_MONO_UNISON_4: case KEYMODE_MONO_UNISON_6: case KEYMODE_MONO_UNISON_8: case KEYMODE_MONO_SMOOTH: case KEYMODE_MONO_RETRIGGER: /* default mono -- use key just pressed */ voice->osc_key[osc] = part->last_key; break; case KEYMODE_POLY: /* use midi key assigned to voice */ voice->osc_key[osc] = voice->midi_key; break; } /* Set oscillator frequencies based on midi note, global transpose value, and optional portamento. state->osc_transpose[osc] is taken into account every sample in the engine. */ if ((state->portamento > 0)) { /* Portamento always starts from previous key hit, no matter which voice. Mono multikey always uses same voice. */ if (state->keymode != KEYMODE_MONO_MULTIKEY) { if (part->prev_key == -1) { voice->osc_freq[osc] = freq_table[state->patch_tune_cc] [256 + part->last_key + state->transpose + state->osc_transpose_cc[osc] - 64]; } else { voice->osc_freq[osc] = freq_table[state->patch_tune_cc] [256 + part->prev_key + state->transpose + state->osc_transpose_cc[osc] - 64]; } } /* Portamento slide calculation works the same for all keymodes. Start portamento now that frequency adjustment is known. */ if ((old_voice == NULL) || (old_voice == voice)) { voice->osc_portamento[osc] = 4.0 * (freq_table[state->patch_tune_cc] [256 + voice->osc_key[osc] + state->transpose + state->osc_transpose_cc[osc] - 64] - voice->osc_freq[osc]) / (sample_t)(voice->portamento_samples - 1); part->portamento_sample = part->portamento_samples; voice->portamento_sample = voice->portamento_samples; } else { voice->osc_portamento[osc] = 4.0 * (freq_table[state->patch_tune_cc] [256 + voice->osc_key[osc] + state->transpose + state->osc_transpose_cc[osc] - 64] - old_voice->osc_freq[osc]) / (sample_t)(voice->portamento_samples - 1); part->portamento_sample = part->portamento_samples; voice->portamento_sample = voice->portamento_samples; /* Mono modes set portamento on voice just finishing to match new voice. */ if ((state->keymode == KEYMODE_MONO_SMOOTH) || (state->keymode == KEYMODE_MONO_RETRIGGER) || (state->keymode == KEYMODE_MONO_UNISON_4) || (state->keymode == KEYMODE_MONO_UNISON_6) || (state->keymode == KEYMODE_MONO_UNISON_8)) { old_voice->osc_portamento[osc] = voice->osc_portamento[osc]; old_voice->portamento_sample = voice->portamento_sample; old_voice->portamento_samples = voice->portamento_samples; } } } /* If portamento is not needed, set the oscillator frequency directly. */ else { voice->osc_freq[osc] = freq_table[state->patch_tune_cc] [256 + voice->osc_key[osc] + state->transpose + state->osc_transpose_cc[osc] - 64]; voice->osc_portamento[osc] = 0.0; voice->portamento_sample = 0; voice->portamento_samples = 0; } } } /* portamento for midi key based lfo */ for (lfo = 0; lfo < NUM_LFOS; lfo++) { if (state->lfo_freq_base[lfo] == FREQ_BASE_MIDI_KEY) { /* decide which key in play to assign to this lfo */ switch (state->keymode) { case KEYMODE_MONO_MULTIKEY: /* use notes in order in lfos */ if (part->cur != NULL) { part->lfo_key[lfo] = part->cur->midi_key; if (part->cur->next != NULL) { part->cur = part->cur->next; } else { part->cur = part->head; } } else { part->lfo_key[lfo] = part->last_key; } break; case KEYMODE_MONO_SMOOTH: case KEYMODE_MONO_RETRIGGER: case KEYMODE_MONO_UNISON_4: case KEYMODE_MONO_UNISON_6: case KEYMODE_MONO_UNISON_8: /* default mono -- use key just pressed */ part->lfo_key[lfo] = part->last_key; break; case KEYMODE_POLY: /* use midi key assigned to allocated voice */ part->lfo_key[lfo] = voice->midi_key; break; } /* Set lfo portamento frequencies based on midi note and transpose value. */ if ((state->portamento > 0) && (part->portamento_samples > 0)) { part->lfo_portamento[lfo] = (freq_table[state->patch_tune_cc] [256 + part->lfo_key[lfo]] - part->lfo_freq[lfo]) / (sample_t) part->portamento_samples; } /* If portamento is not needed, set the lfo frequency directly. */ else { part->lfo_portamento[lfo] = 0.0; part->lfo_freq[lfo] = freq_table[state->patch_tune_cc][256 + part->lfo_key[lfo]]; } } } /* allocate voice (engine actually activates allocated voices) */ voice->allocated = 1; }
/***************************************************************************** * process_note_on() * * Process a note on event for a single part. Add the note to the current * part's keylist and select a voice, stealing one if necessary. All note on * events are processed with process_keytrigger() unless the velocity is set * to zero, and process_note_off() is used instead. *****************************************************************************/ void process_note_on(MIDI_EVENT *event, unsigned int part_num) { VOICE *voice; VOICE *old_voice = NULL; VOICE *loop_voice; PART *part = get_part(part_num); PATCH_STATE *state = get_active_state(part_num); int voice_num; int oldest_age; int free_voice; int steal_voice; int same_key; int osc; int voice_count = 0; /* if this is velocity 0 style note off, fall through */ if (event->velocity > 0) { /* keep track of previous to last key pressed! */ part->prev_key = part->midi_key; part->midi_key = event->note; part->last_key = event->note; /* allocate voice for the different keymodes */ switch (state->keymode) { case KEYMODE_MONO_SMOOTH: old_voice = get_voice(part_num, vnum[part_num]); old_voice->keypressed = -1; /* allocate new voice for staccato in mid-release only. */ if (old_voice->allocated && ((old_voice->cur_amp_interval == ENV_INTERVAL_RELEASE) || (old_voice->cur_amp_interval == ENV_INTERVAL_FADE))) { old_voice->keypressed = -1; old_voice->cur_amp_interval = ENV_INTERVAL_RELEASE; old_voice->cur_amp_sample = -1; PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "voice %2d: ^^^^^^^ Mono-Smooth: " "Fading out voice. (Note On) ^^^^^^^\n", (old_voice->id + 1)); vnum[part_num] = (vnum[part_num] + 1) % setting_polyphony; } break; case KEYMODE_MONO_UNISON_4: voice_count = 4; vnum[part_num] = 0; break; case KEYMODE_MONO_UNISON_6: voice_count = 6; vnum[part_num] = 0; break; case KEYMODE_MONO_UNISON_8: voice_count = 8; vnum[part_num] = 0; break; case KEYMODE_MONO_MULTIKEY: vnum[part_num] = 0; break; case KEYMODE_MONO_RETRIGGER: for (voice_num = 0; voice_num < setting_polyphony; voice_num++) { loop_voice = get_voice(part_num, voice_num); if (loop_voice->allocated) { loop_voice->keypressed = -1; loop_voice->cur_amp_interval = ENV_INTERVAL_RELEASE; loop_voice->cur_amp_sample = -1; old_voice = loop_voice; PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "voice %2d: ^^^^^^^ Mono-Retrigger: " "Fading out voice. (Note On) ^^^^^^^\n", (loop_voice->id + 1)); } } vnum[part_num] = (vnum[part_num] + setting_polyphony - 1) % setting_polyphony; break; case KEYMODE_POLY: vnum[part_num] = 0; /* voice allocation with note stealing */ oldest_age = 0; free_voice = -1; steal_voice = setting_polyphony - 1; same_key = -1; /* look through all the voices */ for (voice_num = 0; voice_num < setting_polyphony; voice_num++) { loop_voice = get_voice(part_num, voice_num); /* priority 1: a free voice */ if (loop_voice->allocated == 0) { free_voice = voice_num; vnum[part_num] = free_voice; voice_num = setting_polyphony; break; } else { if (loop_voice->midi_key == part->midi_key) { PHASEX_DEBUG(DEBUG_CLASS_MIDI_TIMING, DEBUG_COLOR_RED "+++++++++++ " DEBUG_COLOR_DEFAULT); } /* priority 2: find the absolute oldest in play */ if ((same_key == -1) && (loop_voice->age > oldest_age)) { oldest_age = loop_voice->age; steal_voice = voice_num; } } } /* priorities 1 and 2 */ if (free_voice >= 0) { vnum[part_num] = free_voice; } else { vnum[part_num] = steal_voice; PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "*** Part %d: stealing voice %d!\n", (part_num + 1), vnum[part_num]); PHASEX_DEBUG(DEBUG_CLASS_MIDI_TIMING, DEBUG_COLOR_YELLOW "+++++++++++ " DEBUG_COLOR_DEFAULT); } break; } /* keep pointer to current voice around */ voice = get_voice(part_num, vnum[part_num]); /* assign midi note */ voice->midi_key = part->midi_key; voice->keypressed = part->midi_key; /* keep velocity for this note event */ voice->velocity = event->velocity; voice->velocity_target_linear = voice->velocity_coef_linear = part->velocity_target = part->velocity_coef = ((sample_t) event->velocity) * 0.01; voice->velocity_target_log = voice->velocity_coef_log = velocity_gain_table[state->amp_velocity_cc][event->velocity]; for (voice_num = 1; voice_num < voice_count; voice_num++) { if ( vnum[part_num] == voice_num ) continue; loop_voice = get_voice(part_num, voice_num); /* assign midi note */ loop_voice->midi_key = part->midi_key; loop_voice->keypressed = part->midi_key; /* keep velocity for this note event */ loop_voice->velocity = event->velocity; loop_voice->velocity_target_linear = loop_voice->velocity_coef_linear = part->velocity_target = part->velocity_coef = ((sample_t) event->velocity) * 0.01; loop_voice->velocity_target_log = loop_voice->velocity_coef_log = velocity_gain_table[state->amp_velocity_cc][event->velocity]; } if (event->velocity > 0) { part->velocity = event->velocity; PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "voice %2d: Event Note On: part=%d " "voice=%2d note=%3d velocity=%3d keylist=:", (vnum[part_num] + 1), (part_num + 1), (vnum[part_num] + 1), event->note, event->velocity); PHASEX_DEBUG(DEBUG_CLASS_MIDI_TIMING, DEBUG_COLOR_RED "!!!!!!! %d !!!!!!! " DEBUG_COLOR_DEFAULT, event->note); } /* staccato, or no previous notes in play */ if ((part->prev_key == -1) || (part->head == NULL)) { old_voice = NULL; /* put this key at the start of the list */ part->head = & (part->keylist[part->midi_key]); part->head->next = NULL; } /* legato, or previous notes still in play */ else { /* Link this key to the end of the list, unlinking from the middle if necessary. */ part->cur = part->head; part->prev = NULL; while (part->cur != NULL) { PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "%d:", part->cur->midi_key); if (part->cur == &part->keylist[part->midi_key]) { if (part->prev != NULL) { part->prev->next = part->cur->next; } } part->prev = part->cur; part->cur = part->cur->next; } //PHASEX_DEBUG (DEBUG_CLASS_MIDI_NOTE, "\n"); part->cur = & (part->keylist[part->midi_key]); /* if there is no end of the list, link it to the head */ if (part->prev == NULL) { part->head = part->cur; PHASEX_WARN("*** process_note_on(): [part%d] found " "previous key in play with no keylist!\n", (part_num + 1)); } else { part->prev->next = part->cur; } part->cur->next = NULL; } if (event->velocity > 0) { PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "\n"); } /* process parameters dependent on keytrigger events */ process_keytrigger(event, old_voice, voice, part_num); for (voice_num = 0; voice_num < voice_count; voice_num++) { if ( vnum[part_num] == voice_num ) continue; loop_voice = get_voice(part_num, voice_num); process_keytrigger(event, old_voice, loop_voice, part_num); } } /* velocity 0 style note off */ else { process_note_off(event, part_num); } }