void med_play_extras(struct context_data *ctx, struct channel_data *xc, int chn) { struct module_data *m = &ctx->m; struct player_data *p = &ctx->p; struct xmp_module *mod = &m->mod; struct med_module_extras *me; struct med_channel_extras *ce; struct med_instrument_extras *ie; int b, jws = 0, jvs = 0, loop; int temp; if (!HAS_MED_MODULE_EXTRAS(*m)) return; me = (struct med_module_extras *)m->extra; ce = (struct med_channel_extras *)xc->extra; ie = MED_INSTRUMENT_EXTRAS(m->mod.xxi[xc->ins]); /* Handle hold/decay */ /* on the first row of a held note, continue note if ce->hold is 2 * (this is set after pre-fetching the next row and see if we * continue to hold. On remaining rows with hold on, we have the * FX_MED_HOLD effect and ce->hold set to 1. On the last row, see * if ce->hold_count is set (meaning that a note was held) and * ce->hold is 0 (meaning that it's not held anymore). Then * procceed with normal frame counting until decay. */ if (ce->hold_count) { /* was held in the past */ if (!ce->hold && p->frame >= ie->hold) { /* but not now */ SET_NOTE(NOTE_FADEOUT); ce->hold_count = 0; } } else if (ie->hold) { /* has instrument hold */ if (p->frame >= ie->hold && ce->hold == 0) { SET_NOTE(NOTE_FADEOUT); } } if (p->frame == (p->speed - 1) && ce->hold != 2) { ce->hold = 0; } /* Handle synth */ if (me->vol_table[xc->ins] == NULL || me->wav_table[xc->ins] == NULL) { ce->volume = 64; /* we need this in extras_get_volume() */ return; } if (p->frame == 0 && TEST(NEW_NOTE)) { ce->period = xc->period; if (TEST(NEW_INS)) { ce->arp = ce->aidx = 0; ce->vp = ce->vc = ce->vw = 0; ce->wp = ce->wc = ce->ww = 0; ce->env_wav = -1; ce->env_idx = 0; ce->flags &= ~MED_SYNTH_ENV_LOOP; ce->vv = 0; ce->wv = 0; ce->vs = ie->vts; ce->ws = ie->wts; } } if (ce->vs > 0 && ce->vc-- == 0) { ce->vc = ce->vs - 1; if (ce->vw > 0) { ce->vw--; goto skip_vol; } loop = jws = 0; /* Volume commands */ next_vt: switch (b = VT) { case 0xff: /* END */ case 0xfb: /* HLT */ ce->vp--; break; case 0xfe: /* JMP */ if (loop) /* avoid infinite loop */ break; temp = VT; ce->vp = temp; loop = 1; goto next_vt; break; case 0xfa: /* JWS */ jws = VT; break; case 0xf5: /* EN2 */ ce->env_wav = VT; ce->flags |= MED_SYNTH_ENV_LOOP; break; case 0xf4: /* EN1 */ ce->env_wav = VT; break; case 0xf3: /* CHU */ ce->vv = VT; break; case 0xf2: /* CHD */ ce->vv = -VT; break; case 0xf1: /* WAI */ ce->vw = VT; break; case 0xf0: /* SPD */ ce->vs = VT; break; default: if (b >= 0x00 && b <= 0x40) ce->volume = b; } skip_vol: /* volume envelope */ if (ce->env_wav >= 0) { int sid = mod->xxi[xc->ins].sub[ce->env_wav].sid; struct xmp_sample *xxs = &mod->xxs[sid]; if (xxs->len == 0x80) { /* sanity check */ ce->volume = ((int8)xxs->data[ce->env_idx] + 0x80) >> 2; ce->env_idx++; if (ce->env_idx >= 0x80) { if (~ce->flags & MED_SYNTH_ENV_LOOP) { ce->env_wav = -1; } ce->env_idx = 0; } }
void Editor::midi_edit_event(const EventMidi& ev) { BlockList *bl = get_blocklist( get_current_blocklist() ); if (!bl) return; Track_Pattern *pattern_track = dynamic_cast<Track_Pattern*>(bl); if (!pattern_track) return; if (ev.midi_type==EventMidi::MIDI_NOTE_ON) { int column=d->pattern_edit.column; if (d->global_edit.polyphonic_midi_input_enabled) { column+=d->pattern_edit.poly_input_offset; d->pattern_edit.poly_input_offset++; if (column>=pattern_track->get_visible_columns()) return; } if (!pattern_track->is_pos_editable( d->cursor.get_tick_pos() ) ) return; int note=ev.data.note.note; Tick tickpos=d->cursor.get_tick_pos(); int volume=99; if (d->pattern_edit.volume_mask_active) { volume=d->pattern_edit.volume_mask; } else { Track_Pattern::Note note=pattern_track->get_note(Track_Pattern::Position(tickpos,column)); if (note.is_note()) volume=note.volume; } d->undo_stream.begin("Set Note"); SET_NOTE(Track_Pattern::Position(tickpos,column),Track_Pattern::Note(note,volume)); d->undo_stream.end(); play_note_at_cursor(column); if (!d->global_edit.polyphonic_midi_input_enabled) d->cursor.set_pos( d->cursor.get_pos() +1 ); if (d->pattern_edit.volume_mask_active) d->pattern_edit.volume_mask=volume; d->ui_update_notify->volume_mask_changed(); d->ui_update_notify->notify_action( d->undo_stream.get_current_action_text() ); } if (ev.midi_type==EventMidi::MIDI_NOTE_OFF && d->global_edit.polyphonic_midi_input_enabled) { if (d->pattern_edit.poly_input_offset==1) d->cursor.set_pos( d->cursor.get_pos() +1 ); d->pattern_edit.poly_input_offset--; if (d->pattern_edit.poly_input_offset<0) d->pattern_edit.poly_input_offset=0; } }