📄 playmidi.c
字号:
voice[i].velocity=e->b; recompute_amp(i); apply_envelope_to_amp(i); return; }}static void adjust_panning(int c){ int i=voices; while (i--) if ((voice[i].channel==c) && (voice[i].status==VOICE_ON || voice[i].status==VOICE_SUSTAINED)) { if (voice[i].clone_type != NOT_CLONE) continue; voice[i].panning=channel[c].panning; recompute_amp(i); apply_envelope_to_amp(i); }}static void drop_sustain(int c){ int i=voices; while (i--) if (voice[i].status==VOICE_SUSTAINED && voice[i].channel==c) finish_note(i);}static void adjust_pitchbend(int c){ int i=voices; while (i--) if (voice[i].status!=VOICE_FREE && voice[i].channel==c) { recompute_freq(i); }}static void adjust_volume(int c){ int i=voices; while (i--) if (voice[i].channel==c && (voice[i].status==VOICE_ON || voice[i].status==VOICE_SUSTAINED)) { recompute_amp(i); apply_envelope_to_amp(i); }}static void seek_forward(int32 until_time){ reset_voices(); while (current_event->time < until_time) { switch(current_event->type) { /* All notes stay off. Just handle the parameter changes. */ case ME_PITCH_SENS: channel[current_event->channel].pitchsens= current_event->a; channel[current_event->channel].pitchfactor=0; break; case ME_PITCHWHEEL: channel[current_event->channel].pitchbend= current_event->a + current_event->b * 128; channel[current_event->channel].pitchfactor=0; break; case ME_MAINVOLUME: channel[current_event->channel].volume=current_event->a; break; case ME_MASTERVOLUME: adjust_master_volume(current_event->a + (current_event->b <<7)); break; case ME_PAN: channel[current_event->channel].panning=current_event->a; break; case ME_EXPRESSION: channel[current_event->channel].expression=current_event->a; break; case ME_PROGRAM: /* if (ISDRUMCHANNEL(current_event->channel)) */ if (channel[current_event->channel].kit) /* Change drum set */ channel[current_event->channel].bank=current_event->a; else channel[current_event->channel].program=current_event->a; break; case ME_SUSTAIN: channel[current_event->channel].sustain=current_event->a; break; case ME_REVERBERATION: channel[current_event->channel].reverberation=current_event->a; break; case ME_CHORUSDEPTH: channel[current_event->channel].chorusdepth=current_event->a; break; case ME_HARMONICCONTENT: channel[current_event->channel].harmoniccontent=current_event->a; break; case ME_RELEASETIME: channel[current_event->channel].releasetime=current_event->a; break; case ME_ATTACKTIME: channel[current_event->channel].attacktime=current_event->a; break; case ME_BRIGHTNESS: channel[current_event->channel].brightness=current_event->a; break; case ME_TONE_KIT: if (current_event->a==SFX_BANKTYPE) { channel[current_event->channel].sfx=SFXBANK; channel[current_event->channel].kit=0; } else { channel[current_event->channel].sfx=0; channel[current_event->channel].kit=current_event->a; } break; case ME_RESET_CONTROLLERS: reset_controllers(current_event->channel); break; case ME_TONE_BANK: channel[current_event->channel].bank=current_event->a; break; case ME_EOT: current_sample=current_event->time; return; } current_event++; } /*current_sample=current_event->time;*/ if (current_event != event_list) current_event--; current_sample=until_time;}static void skip_to(int32 until_time){ if (current_sample > until_time) current_sample=0; reset_midi(); buffered_count=0; buffer_pointer=common_buffer; current_event=event_list; if (until_time) seek_forward(until_time); ctl->reset();}static int apply_controls(void){ int rc, i, did_skip=0; int32 val; /* ASCII renditions of CD player pictograms indicate approximate effect */ do switch(rc=ctl->read(&val)) { case RC_QUIT: /* [] */ case RC_LOAD_FILE: case RC_NEXT: /* >>| */ case RC_REALLY_PREVIOUS: /* |<< */ return rc; case RC_CHANGE_VOLUME: if (val>0 || amplification > -val) amplification += val; else amplification=0; if (amplification > MAX_AMPLIFICATION) amplification=MAX_AMPLIFICATION; adjust_amplification(); for (i=0; i<voices; i++) if (voice[i].status != VOICE_FREE) { recompute_amp(i); apply_envelope_to_amp(i); } ctl->master_volume(amplification); break; case RC_PREVIOUS: /* |<< */ if (current_sample < 2*play_mode->rate) return RC_REALLY_PREVIOUS; return RC_RESTART; case RC_RESTART: /* |<< */ skip_to(0); did_skip=1; break; case RC_JUMP: if (val >= sample_count) return RC_NEXT; skip_to(val); return rc; case RC_FORWARD: /* >> */ if (val+current_sample >= sample_count) return RC_NEXT; skip_to(val+current_sample); did_skip=1; break; case RC_BACK: /* << */ if (current_sample > val) skip_to(current_sample-val); else skip_to(0); /* We can't seek to end of previous song. */ did_skip=1; break; } while (rc!= RC_NONE); /* Advertise the skip so that we stop computing the audio buffer */ if (did_skip) return RC_JUMP; else return rc;}static void do_compute_data(uint32 count){ int i; if (!count) return; /* (gl) */ memset(buffer_pointer, 0, count * num_ochannels * 4); for (i=0; i<voices; i++) { if(voice[i].status != VOICE_FREE) { if (!voice[i].sample_offset && voice[i].echo_delay_count) { if ((uint32)voice[i].echo_delay_count >= count) voice[i].echo_delay_count -= count; else { mix_voice(buffer_pointer+voice[i].echo_delay_count, i, count-voice[i].echo_delay_count); voice[i].echo_delay_count = 0; } } else mix_voice(buffer_pointer, i, count); } } current_sample += count;}/* count=0 means flush remaining buffered data to output device, then flush the device itself */static int compute_data(void *stream, int32 count){ int rc, channels; if ( play_mode->encoding & PE_MONO ) channels = 1; else channels = num_ochannels; if (!count) { if (buffered_count) s32tobuf(stream, common_buffer, channels*buffered_count); buffer_pointer=common_buffer; buffered_count=0; return RC_NONE; } while ((count+buffered_count) >= AUDIO_BUFFER_SIZE) { do_compute_data(AUDIO_BUFFER_SIZE-buffered_count); count -= AUDIO_BUFFER_SIZE-buffered_count; s32tobuf(stream, common_buffer, channels*AUDIO_BUFFER_SIZE); buffer_pointer=common_buffer; buffered_count=0; ctl->current_time(current_sample); if ((rc=apply_controls())!=RC_NONE) return rc; } if (count>0) { do_compute_data(count); buffered_count += count; buffer_pointer += count * channels; } return RC_NONE;}int Timidity_PlaySome(void *stream, int samples){ int rc = RC_NONE; int32 end_sample; if ( ! midi_playing ) { return RC_NONE; } end_sample = current_sample+samples; while ( current_sample < end_sample ) { /* Handle all events that should happen at this time */ while (current_event->time <= current_sample) { switch(current_event->type) { /* Effects affecting a single note */ case ME_NOTEON: current_event->a += channel[current_event->channel].transpose; if (!(current_event->b)) /* Velocity 0? */ note_off(current_event); else note_on(current_event); break; case ME_NOTEOFF: current_event->a += channel[current_event->channel].transpose; note_off(current_event); break; case ME_KEYPRESSURE: adjust_pressure(current_event); break; /* Effects affecting a single channel */ case ME_PITCH_SENS: channel[current_event->channel].pitchsens=current_event->a; channel[current_event->channel].pitchfactor=0; break; case ME_PITCHWHEEL: channel[current_event->channel].pitchbend= current_event->a + current_event->b * 128; channel[current_event->channel].pitchfactor=0; /* Adjust pitch for notes already playing */ adjust_pitchbend(current_event->channel); ctl->pitch_bend(current_event->channel, channel[current_event->channel].pitchbend); break; case ME_MAINVOLUME: channel[current_event->channel].volume=current_event->a; adjust_volume(current_event->channel); ctl->volume(current_event->channel, current_event->a); break; case ME_MASTERVOLUME: adjust_master_volume(current_event->a + (current_event->b <<7)); break; case ME_REVERBERATION: channel[current_event->channel].reverberation=current_event->a; break; case ME_CHORUSDEPTH: channel[current_event->channel].chorusdepth=current_event->a; break; case ME_PAN: channel[current_event->channel].panning=current_event->a; if (adjust_panning_immediately) adjust_panning(current_event->channel); ctl->panning(current_event->channel, current_event->a); break; case ME_EXPRESSION: channel[current_event->channel].expression=current_event->a; adjust_volume(current_event->channel); ctl->expression(current_event->channel, current_event->a); break; case ME_PROGRAM: /* if (ISDRUMCHANNEL(current_event->channel)) { */ if (channel[current_event->channel].kit) { /* Change drum set */ channel[current_event->channel].bank=current_event->a; } else { channel[current_event->channel].program=current_event->a; } ctl->program(current_event->channel, current_event->a); break; case ME_SUSTAIN: channel[current_event->channel].sustain=current_event->a; if (!current_event->a) drop_sustain(current_event->channel); ctl->sustain(current_event->channel, current_event->a); break; case ME_RESET_CONTROLLERS: reset_controllers(current_event->channel); redraw_controllers(current_event->channel); break; case ME_ALL_NOTES_OFF: all_notes_off(current_event->channel); break; case ME_ALL_SOUNDS_OFF: all_sounds_off(current_event->channel); break; case ME_HARMONICCONTENT: channel[current_event->channel].harmoniccontent=current_event->a; break; case ME_RELEASETIME: channel[current_event->channel].releasetime=current_event->a; break; case ME_ATTACKTIME: channel[current_event->channel].attacktime=current_event->a; break; case ME_BRIGHTNESS: channel[current_event->channel].brightness=current_event->a; break; case ME_TONE_BANK: channel[current_event->channel].bank=current_event->a; break; case ME_TONE_KIT: if (current_event->a==SFX_BANKTYPE) { channel[current_event->channel].sfx=SFXBANK; channel[current_event->channel].kit=0; } else { channel[current_event->channel].sfx=0; channel[current_event->channel].kit=current_event->a; } break; case ME_EOT: /* Give the last notes a couple of seconds to decay */ ctl->cmsg(CMSG_INFO, VERB_VERBOSE, "Playing time: ~%d seconds", current_sample/play_mode->rate+2); ctl->cmsg(CMSG_INFO, VERB_VERBOSE, "Notes cut: %d", cut_notes); ctl->cmsg(CMSG_INFO, VERB_VERBOSE, "Notes lost totally: %d", lost_notes); midi_playing = 0; return RC_TUNE_END; } current_event++; } if (current_event->time > end_sample) rc=compute_data(stream, end_sample-current_sample); else rc=compute_data(stream, current_event->time-current_sample); ctl->refresh(); if ( (rc!=RC_NONE) && (rc!=RC_JUMP)) break; } return rc;}void Timidity_SetVolume(int volume){ int i; if (volume > MAX_AMPLIFICATION) amplification=MAX_AMPLIFICATION; else if (volume < 0) amplification=0; else amplification=volume; adjust_amplification(); for (i=0; i<voices; i++) if (voice[i].status != VOICE_FREE) { recompute_amp(i); apply_envelope_to_amp(i); } ctl->master_volume(amplification);}MidiSong *Timidity_LoadSong(char *midifile){ MidiSong *song; int32 events; SDL_RWops *rw; /* Allocate memory for the song */ song = (MidiSong *)safe_malloc(sizeof(*song)); memset(song, 0, sizeof(*song)); /* Open the file */ strcpy(midi_name, midifile); rw = SDL_RWFromFile(midifile, "rb"); if ( rw != NULL ) { song->events=read_midi_file(rw, &events, &song->samples); SDL_RWclose(rw); } /* Make sure everything is okay */ if (!song->events) { free(song); song = NULL; } return(song);}MidiSong *Timidity_LoadSong_RW(SDL_RWops *rw){ MidiSong *song; int32 events; /* Allocate memory for the song */ song = (MidiSong *)safe_malloc(sizeof(*song)); memset(song, 0, sizeof(*song)); strcpy(midi_name, "SDLrwops source"); song->events=read_midi_file(rw, &events, &song->samples); /* Make sure everything is okay */ if (!song->events) { free(song); song = NULL; } return(song);}void Timidity_Start(MidiSong *song){ load_missing_instruments(); adjust_amplification(); sample_count = song->samples; event_list = song->events; lost_notes=cut_notes=0; skip_to(0); midi_playing = 1;}int Timidity_Active(void){ return(midi_playing);}void Timidity_Stop(void){ midi_playing = 0;}void Timidity_FreeSong(MidiSong *song){ if (free_instruments_afterwards) free_instruments(); free(song->events); free(song);}void Timidity_Close(void){ if (resample_buffer) { free(resample_buffer); resample_buffer=NULL; } if (common_buffer) { free(common_buffer); common_buffer=NULL; } free_instruments(); free_pathlist();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -