static int main_loop(synth_t *synth) { const SDLKey keyboard[] = { // c c# d d# e f f# g g# a a# b c d e SDLK_z, SDLK_s, SDLK_x, SDLK_d, SDLK_c, SDLK_v, SDLK_g, SDLK_b, SDLK_h, SDLK_n, SDLK_j, SDLK_m, SDLK_COMMA, SDLK_l, SDLK_PERIOD, SDLK_q, SDLK_2, SDLK_w, SDLK_3, SDLK_e, SDLK_r, SDLK_5, SDLK_t, SDLK_6, SDLK_y, SDLK_7, SDLK_u, SDLK_i, SDLK_9, SDLK_o, SDLK_0, SDLK_p }; int notes[] = { // c c# d d# e f f# g g# a a# b c d e 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, }; int num_keys = sizeof(keyboard)/sizeof(*keyboard); int base_octave = 4; bool quit = false; while(!quit) { const float background[] = { 0.2, 0.4, 0.7, 1.0 }; glClearBufferfv(GL_COLOR, 0, background); SDL_GL_SwapBuffers(); SDL_Event event; while(SDL_PollEvent(&event)) { if(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE) quit = true; else if(event.type == SDL_KEYDOWN && event.key.keysym.sym >= SDLK_F1 && event.key.keysym.sym <= SDLK_F12) base_octave = event.key.keysym.sym - SDLK_F1; else if(event.type == SDL_KEYDOWN) { for(int i = 0; i < num_keys; ++i) { if(keyboard[i] != event.key.keysym.sym) continue; SDL_LockAudio(); synth->instruments->carrier.freq = note_freq(base_octave * 12 + notes[i]); adsr_trigger(&synth->instruments[0].adsr); SDL_UnlockAudio(); } } } } return 0; }
/* a helper function to activate a voice for a patch */ inline static void patch_trigger_patch (Patch* p, int note, float vel, Tick ticks) { int i; PatchVoice* v; int index; /* the index we ended up settling on */ float key_track; bool legato; if (p->sample->sp == NULL) return; if (p->upper_note == p->lower_note) key_track = 1.0; else key_track = (float)(note - p->lower_note) / (p->upper_note - p->lower_note); legato = patch_bool_get(&p->legato, p); if (p->mono && legato) { /* half of the previous logic operating here was ignored. * removing it left only logic which could be simplified * to the following: */ v = p->voices[0]; index = 0; if (!v->active || v->released) v->vel = vel; else { /* don't trigger voice, do legato instead: */ v->ticks = ticks; v->note = note; v->vel = vel; v->relset = -1; /* cancel any pending release */ v->relmode = RELEASE_NONE; v->released = false; v->to_end = false; v->xfade = false; v->loop = p->play_mode & PATCH_PLAY_LOOP; v->key_track = key_track; v->portamento = patch_bool_get(&p->porta, p); v->porta_secs = patch_float_get(&p->porta_secs, p); prepare_pitch(p, v, note); return; } } else /* mono w/o legato, or poly */ { int oldest = 0; Tick oldestticks = ticks; /* find a free voice slot and determine the oldest running voice */ for (i = 0; i < PATCH_VOICE_COUNT; ++i) { if (p->voices[i]->ticks <= oldestticks) { oldestticks = p->voices[i]->ticks; oldest = i; } if (!p->voices[i]->active) break; } /* take the oldest running voice's slot if we couldn't find an * empty one */ index = (i == PATCH_VOICE_COUNT) ? oldest : i; } v = p->voices[index]; /* shutdown any running voices if monophonic */ if (p->mono) patch_release_patch(p, -69, RELEASE_CUTOFF); /* fill in our voice */ v->ticks = ticks; v->relset = -1; /* N/A at this time */ v->relmode = RELEASE_NONE; v->released = false; v->to_end = false; /* TRUE after loop */ v->xfade = false; v->loop = p->play_mode & PATCH_PLAY_LOOP; v->note = note; v->key_track = key_track; v->legato = legato; v->portamento = patch_bool_get(&p->porta, p); v->porta_secs = patch_float_get(&p->porta_secs, p); if (!(p->mono && v->legato)) v->vel = vel; if (!p->mono) v->fll = v->fbl = v->flr = v->fbr = 0; for (i = 0; i < MAX_MOD_SLOTS; ++i) { v->amp_mod[i] = patch_mod_id_to_pointer(p->amp.mod_id[i], p, v); v->pan_mod[i] = patch_mod_id_to_pointer(p->pan.mod_id[i], p, v); v->ffreq_mod[i] = patch_mod_id_to_pointer(p->ffreq.mod_id[i], p, v); v->freso_mod[i] = patch_mod_id_to_pointer(p->freso.mod_id[i], p, v); v->pitch_mod[i] = patch_mod_id_to_pointer(p->pitch.mod_id[i], p, v); } if (!(p->mono && v->legato && v->active)) playstate_init_fade_in(p, v); prepare_pitch(p, v, note); for (i = 0; i < VOICE_MAX_ENVS; i++) { if (p->env_params[i].active) { adsr_set_params(v->env[i], &p->env_params[i]); adsr_trigger(v->env[i], key_track, vel); } } for (i = 0; i < VOICE_MAX_LFOS; i++) { if (p->vlfo_params[i].active) { float const* src; src = patch_mod_id_to_pointer(p->vlfo_params[i].fm1_id, p, v); lfo_set_fm1(v->lfo[i], src); src = patch_mod_id_to_pointer(p->vlfo_params[i].fm2_id, p, v); lfo_set_fm2(v->lfo[i], src); src = patch_mod_id_to_pointer(p->vlfo_params[i].am1_id, p, v); lfo_set_am1(v->lfo[i], src); src = patch_mod_id_to_pointer(p->vlfo_params[i].am2_id, p, v); lfo_set_am2(v->lfo[i], src); lfo_trigger(v->lfo[i], &p->vlfo_params[i]); } } /* mark our territory */ v->active = true; }