From e97bc5db814b844ef2e4ee92f8a683031853dadb Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Tue, 8 Sep 2009 17:56:21 +0000 Subject: Program two voices for double voice instruments. Subversion-branch: /branches/opl-branch Subversion-revision: 1660 --- src/i_oplmusic.c | 164 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 91 insertions(+), 73 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index e9fdb395..8ec47b80 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -49,7 +49,7 @@ #define GENMIDI_HEADER "#OPL_II#" #define GENMIDI_FLAG_FIXED 0x0001 /* fixed pitch */ -#define GENMIDI_FLAG_2VOICE 0x0002 /* double voice (OPL3) */ +#define GENMIDI_FLAG_2VOICE 0x0004 /* double voice (OPL3) */ typedef struct { @@ -76,8 +76,7 @@ typedef struct byte fine_tuning; byte fixed_note; - genmidi_voice_t opl2_voice; - genmidi_voice_t opl3_voice; + genmidi_voice_t voices[2]; } PACKEDATTR genmidi_instr_t; // Data associated with a channel of a track that is currently playing. @@ -129,6 +128,11 @@ struct opl_voice_s // Currently-loaded instrument data genmidi_instr_t *current_instr; + // The voice number in the instrument to use. + // This is normally set to zero; if this is a double voice + // instrument, it may be one. + unsigned int current_instr_voice; + // The channel currently using this voice. opl_channel_data_t *channel; @@ -555,20 +559,25 @@ static void LoadOperatorData(int operator, genmidi_op_t *data, // Set the instrument for a particular voice. -static void SetVoiceInstrument(opl_voice_t *voice, genmidi_instr_t *instr) +static void SetVoiceInstrument(opl_voice_t *voice, + genmidi_instr_t *instr, + unsigned int instr_voice) { genmidi_voice_t *data; unsigned int modulating; // Instrument already set for this channel? - if (voice->current_instr == instr) + if (voice->current_instr == instr + && voice->current_instr_voice == instr_voice) { return; } voice->current_instr = instr; - data = &instr->opl2_voice; + voice->current_instr_voice = instr_voice; + + data = &instr->voices[instr_voice]; // Are we usind modulated feedback mode? @@ -630,7 +639,7 @@ static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume) voice->note_volume = volume; - opl_voice = &voice->current_instr->opl2_voice; + opl_voice = &voice->current_instr->voices[voice->current_instr_voice]; // Multiply note volume and channel volume to get the actual volume. @@ -765,7 +774,7 @@ static boolean I_OPL_InitMusic(void) voice = GetFreeVoice(); instr_num = rand() % 100; - SetVoiceInstrument(voice, &main_instrs[instr_num].opl2_voice); + SetVoiceInstrument(voice, &main_instrs[instr_num], 0); OPL_SetCallback(0, TestCallback, voice); } @@ -785,32 +794,18 @@ static void I_OPL_SetMusicVolume(int volume) current_music_volume = volume; } -static opl_voice_t *FindVoiceForKey(opl_channel_data_t *channel, int key) -{ - unsigned int i; - - for (i=0; iindex, voice->freq >> 8); } // Get the frequency that we should be using for a voice. -static void NoteOffEvent(opl_track_data_t *track, midi_event_t *event) +static void KeyOffEvent(opl_track_data_t *track, midi_event_t *event) { - opl_voice_t *voice; opl_channel_data_t *channel; + unsigned int key; + unsigned int i; printf("note off: channel %i, %i, %i\n", event->data.channel.channel, @@ -818,21 +813,22 @@ static void NoteOffEvent(opl_track_data_t *track, midi_event_t *event) event->data.channel.param2); channel = &track->channels[event->data.channel.channel]; + key = event->data.channel.param1; - // Find the voice being used to play the note. - - voice = FindVoiceForKey(channel, event->data.channel.param1); + // Turn off voices being used to play this key. + // If it is a double voice instrument there will be two. - if (voice == NULL) + for (i=0; idata.channel.channel, - event->data.channel.param1, - event->data.channel.param2); - - // The channel. - - channel = &track->channels[event->data.channel.channel]; - key = event->data.channel.param1; - volume = event->data.channel.param2; - - // Percussion channel (10) is treated differently. - - if (event->data.channel.channel == 9) - { - if (key < 35 || key > 81) - { - return; - } - - instrument = &percussion_instrs[key - 35]; - } - else - { - instrument = channel->instrument; - } // Find a voice to use for this new note. @@ -920,7 +893,7 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) if (voice == NULL) { - printf("\tno free voice\n"); + printf("\tno free voice for voice %i of instrument\n", instrument_voice); return; } @@ -941,7 +914,7 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) // Program the voice with the instrument data: - SetVoiceInstrument(voice, instrument); + SetVoiceInstrument(voice, instrument, 0); // Set the volume level. @@ -953,6 +926,51 @@ static void NoteOnEvent(opl_track_data_t *track, midi_event_t *event) UpdateVoiceFrequency(voice); } +static void KeyOnEvent(opl_track_data_t *track, midi_event_t *event) +{ + genmidi_instr_t *instrument; + opl_channel_data_t *channel; + unsigned int key; + unsigned int volume; + + printf("note on: channel %i, %i, %i\n", + event->data.channel.channel, + event->data.channel.param1, + event->data.channel.param2); + + // The channel. + + channel = &track->channels[event->data.channel.channel]; + key = event->data.channel.param1; + volume = event->data.channel.param2; + + // Percussion channel (10) is treated differently. + + if (event->data.channel.channel == 9) + { + if (key < 35 || key > 81) + { + return; + } + + instrument = &percussion_instrs[key - 35]; + } + else + { + instrument = channel->instrument; + } + + // Find and program a voice for this instrument. If this + // is a double voice instrument, we must do this twice. + + VoiceKeyOn(channel, instrument, 0, key, volume); + + if ((instrument->flags & GENMIDI_FLAG_2VOICE) != 0) + { + VoiceKeyOn(channel, instrument, 1, key, volume); + } +} + static void ProgramChangeEvent(opl_track_data_t *track, midi_event_t *event) { int channel; @@ -1075,11 +1093,11 @@ static void ProcessEvent(opl_track_data_t *track, midi_event_t *event) switch (event->event_type) { case MIDI_EVENT_NOTE_OFF: - NoteOffEvent(track, event); + KeyOffEvent(track, event); break; case MIDI_EVENT_NOTE_ON: - NoteOnEvent(track, event); + KeyOnEvent(track, event); break; case MIDI_EVENT_CONTROLLER: @@ -1284,7 +1302,7 @@ static void I_OPL_StopSong(void) { if (voices[i].channel != NULL) { - VoiceNoteOff(&voices[i]); + VoiceKeyOff(&voices[i]); ReleaseVoice(&voices[i]); } } -- cgit v1.2.3