diff options
Diffstat (limited to 'engines/sci/sfx/softseq/opl2.cpp')
-rw-r--r-- | engines/sci/sfx/softseq/opl2.cpp | 579 |
1 files changed, 0 insertions, 579 deletions
diff --git a/engines/sci/sfx/softseq/opl2.cpp b/engines/sci/sfx/softseq/opl2.cpp deleted file mode 100644 index 21fe41962c..0000000000 --- a/engines/sci/sfx/softseq/opl2.cpp +++ /dev/null @@ -1,579 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/*************************************************************************** - opl2.c Copyright (C) 2002/04 Solomon Peachy, Christoph Reichenbach - - This program may be modified and copied freely according to the terms of - the GNU general public license (GPL), as long as the above copyright - notice and the licensing information contained herein are preserved. - - Please refer to www.gnu.org for licensing details. - - This work is provided AS IS, without warranty of any kind, expressed or - implied, including but not limited to the warranties of merchantibility, - noninfringement, and fitness for a specific purpose. The author will not - be held liable for any damage caused by this work or derivatives of it. - - By using this source code, you agree to the licensing terms as stated - above. - -***************************************************************************/ - -#include "common/util.h" - -#include "sci/tools.h" -#include "sci/sfx/iterator.h" -#include "sci/sfx/softseq.h" -#include "sci/sfx/adlib_sbi.h" -#include "sci/sfx/sci_midi.h" - -#include "sound/fmopl.h" - -namespace Sci { - -// FIXME: Instead of hardcoding SAMPLE_RATE we should call Mixer::getOutputRate() -#ifdef __DC__ -#define SAMPLE_RATE 22050 -#elif defined (__WII__) -#define SAMPLE_RATE 48000 -#else -#define SAMPLE_RATE 44100 -#endif - -#define CHANNELS SFX_PCM_MONO -#define STEREO 0 - -/* local function declarations */ - -static void opl2_allstop(sfx_softseq_t *self); - -//#define DEBUG_ADLIB - -/* portions shamelessly lifted from claudio's XMP */ -/* other portions lifted from sound/opl3.c in the Linux kernel */ - -static int ready = 0; - -static int register_base[11] = { - 0x20, 0x23, 0x40, 0x43, - 0x60, 0x63, 0x80, 0x83, - 0xe0, 0xe3, 0xc0 -}; - -static int register_offset[12] = { - /* Channel 1 2 3 4 5 6 7 8 9 */ - /* Operator 1 */ 0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12, 0x18, 0x19, 0x1A - -}; - -static int ym3812_note[13] = { - 0x157, 0x16b, 0x181, 0x198, 0x1b0, 0x1ca, - 0x1e5, 0x202, 0x220, 0x241, 0x263, 0x287, - 0x2ae -}; - -static uint8 sci_adlib_vol_base[16] = { - 0x00, 0x11, 0x15, 0x19, 0x1D, 0x22, 0x26, 0x2A, - 0x2E, 0x23, 0x37, 0x3B, 0x3F, 0x3F, 0x3F, 0x3F -}; -static uint8 sci_adlib_vol_tables[16][64]; - -/* back to your regularly scheduled definitions */ - -static uint8 instr[MIDI_CHANNELS]; -static uint16 pitch[MIDI_CHANNELS]; -static uint8 vol[MIDI_CHANNELS]; -static uint8 pan[MIDI_CHANNELS]; -static int free_voices = ADLIB_VOICES; -static uint8 oper_note[ADLIB_VOICES]; -static uint8 oper_chn[ADLIB_VOICES]; - -static FM_OPL *ym3812 = NULL; - -static uint8 adlib_reg[256]; -static uint8 adlib_master; - - -/* initialise note/operator lists, etc. */ -void adlibemu_init_lists() { - int i; - - int j; - - for (i = 0 ; i < 16 ; i++) { - for (j = 0; j < 64 ; j++) { - sci_adlib_vol_tables[i][j] = ((uint16)sci_adlib_vol_base[i]) * j / 63; - } - } - - for (i = 0; i < MIDI_CHANNELS ; i++) { - pitch[i] = 8192; /* center the pitch wheel */ - } - - free_voices = ADLIB_VOICES; - - memset(instr, 0, sizeof(instr)); - memset(vol, 0x7f, sizeof(vol)); - memset(pan, 0x3f, sizeof(pan)); - memset(adlib_reg, 0, sizeof(adlib_reg)); - memset(oper_chn, 0xff, sizeof(oper_chn)); - memset(oper_note, 0xff, sizeof(oper_note)); - adlib_master = 12; -} - -/* more shamelessly lifted from xmp and adplug. And altered. :) */ - -static void opl_write(int a, int v) { - adlib_reg[a] = v; - OPLWrite(ym3812, 0x388, a); - OPLWrite(ym3812, 0x389, v); -} - -void synth_setpatch(int voice, uint8 *data) { - int i; - - opl_write(0xBD, 0); - - for (i = 0; i < 10; i++) - opl_write(register_base[i] + register_offset[voice], data[i]); - - opl_write(register_base[10] + voice, data[10]); - - /* mute voice after patch change */ - opl_write(0xb0 + voice, adlib_reg[0xb0+voice] & 0xdf); - -#ifdef DEBUG_ADLIB - for (i = 0; i < 10; i++) - printf("%02x ", adlib_reg[register_base[i] + register_offset[voice]]); - printf("%02x ", adlib_reg[register_base[10] + voice]); -#endif - -} - -void synth_setvolume(int voice, int volume) { - int8 level1, level2; - - level1 = ~adlib_reg[register_base[2] + register_offset[voice]] & 0x3f; - level2 = ~adlib_reg[register_base[3] + register_offset[voice]] & 0x3f; - - if (level1) { - level1 += sci_adlib_vol_tables[adlib_master][volume>>1]; - } - - if (level2) { - level2 += sci_adlib_vol_tables[adlib_master][volume>>1]; - } - - if (level1 > 0x3f) - level1 = 0x3f; - if (level1 < 0) - level1 = 0; - - if (level2 > 0x3f) - level2 = 0x3f; - if (level2 < 0) - level2 = 0; - - /* algorithm-dependent; we may need to set both operators. */ - if (adlib_reg[register_base[10] + voice] & 1) - opl_write(register_base[2] + register_offset[voice], - (uint8)((~level1 &0x3f) | - (adlib_reg[register_base[2] + register_offset[voice]]&0xc0))); - - opl_write(register_base[3] + register_offset[voice], - (uint8)((~level2 &0x3f) | - (adlib_reg[register_base[3] + register_offset[voice]]&0xc0))); - -} - -void synth_setnote(int voice, int note, int bend) { - int n, fre, oct; - float delta; - - delta = 0; - - n = note % 12; - - if (bend < 8192) - bend = 8192 - bend; - delta = pow(2.0, (float)(bend % 8192) / 8192.0); - - if (bend > 8192) - fre = (int)(ym3812_note[n] * delta); - else - fre = (int)(ym3812_note[n] / delta); - - oct = note / 12 - 1; - - if (oct < 0) - oct = 0; - - opl_write(0xa0 + voice, fre & 0xff); - opl_write(0xb0 + voice, - 0x20 | ((oct << 2) & 0x1c) | ((fre >> 8) & 0x03)); -#ifdef DEBUG_ADLIB - printf("-- %02x %02x\n", adlib_reg[0xa0+voice], adlib_reg[0xb0+voice]); -#endif - -} - - -/* back to your regularly scheduled driver */ - -int adlibemu_stop_note(int chn, int note, int velocity) { - int i, op = 255; - - // sciprintf("Note off %d %d %d\n", chn, note, velocity); - - for (i = 0;i < ADLIB_VOICES && op == 255;i++) { - if (oper_chn[i] == chn) - if (oper_note[i] == note) - op = i; - } - - if (op == 255) { -#ifdef DEBUG_ADLIB - printf("ADLIB: can't stop note: C%02x N%02x V%02x\n", chn, note, velocity); - printf("C "); - for (i = 0; i < ADLIB_VOICES ; i++) { - printf("%02x ", oper_chn[i]); - } - printf("\n"); - printf("N "); - for (i = 0; i < ADLIB_VOICES ; i++) { - printf("%02x ", oper_note[i]); - } - printf("\n"); -#endif - return -1; /* that note isn't playing.. */ - } - - opl_write(0xb0 + op, (adlib_reg[0xb0+op] & 0xdf)); - - oper_chn[op] = 255; - oper_note[op] = 255; - - free_voices++; - -#ifdef DEBUG_ADLIB - printf("stop voice %d (%d rem): C%02x N%02x V%02x\n", op, free_voices, chn, note, velocity); -#endif - - return 0; -} - -int adlibemu_start_note(int chn, int note, int velocity) { - int op, volume, inst = 0; - - // sciprintf("Note on %d %d %d\n", chn, note, velocity); - - if (velocity == 0) { - return adlibemu_stop_note(chn, note, velocity); - } - - if (free_voices <= 0) { - printf("ADLIB: All voices full\n"); /* XXX implement overflow code */ - return -1; - } - - for (op = 0; op < ADLIB_VOICES ; op++) - if (oper_chn[op] == 255) - break; - - if (op == ADLIB_VOICES) { - printf("ADLIB: WTF? We couldn't find a voice yet it we have %d left.\n", free_voices); - return -1; - } - - /* Scale channel volume */ - volume = velocity * vol[chn] / 127; - inst = instr[chn]; - - synth_setpatch(op, adlib_sbi[inst]); - synth_setvolume(op, volume); - synth_setnote(op, note, pitch[chn]); - - oper_chn[op] = chn; - oper_note[op] = note; - free_voices--; - -#ifdef DEBUG_ADLIB - printf("play voice %d (%d rem): C%02x N%02x V%02x/%02x P%02x (%02x/%02x)\n", op, free_voices, chn, note, velocity, volume, inst, - adlib_reg[register_base[2] + register_offset[op]] & 0x3f, - adlib_reg[register_base[3] + register_offset[op]] & 0x3f); -#endif - - return 0; -} - -static void adlibemu_update_pitch(int chn, int note, int newpitch) { - int i; - int matched = 0; - - pitch[chn] = newpitch; - - for (i = 0;i < ADLIB_VOICES;i++) { - if (oper_chn[i] == chn) { - matched++; - synth_setnote(i, oper_note[i], newpitch); - } - } - -// printf("Matched %d notes on channel %d.\n", matched, chn); -} - -void test_adlib() { - - int voice = 0; -#if 0 - uint8 data[] = { 0x25, 0x21, 0x48, 0x48, 0xf0, 0xf2, 0xf0, 0xa5, 0x00, 0x00, 0x06 }; -#else - uint8 *data = adlib_sbi[0x0a]; -#endif - -#if 1 - opl_write(register_base[0] + register_offset[voice], data[0]); - opl_write(register_base[1] + register_offset[voice], data[1]); - opl_write(register_base[2] + register_offset[voice], data[2]); - opl_write(register_base[3] + register_offset[voice], data[3]); - opl_write(register_base[4] + register_offset[voice], data[4]); - opl_write(register_base[5] + register_offset[voice], data[5]); - opl_write(register_base[6] + register_offset[voice], data[6]); - opl_write(register_base[7] + register_offset[voice], data[7]); - opl_write(register_base[8] + register_offset[voice], data[8]); - opl_write(register_base[9] + register_offset[voice], data[9]); - opl_write(register_base[10] + register_offset[voice], data[10]); -#else - synth_setpatch(voice, data); -#endif - -#if 0 - opl_write(0xA0 + voice, 0x57); - opl_write(0xB0 + voice, 0x2d); -#else - synth_setvolume(voice, 0x50); - synth_setnote(voice, 0x30, 0); -#endif - - /* - instr[0x0e] = 0x0a; - instr[0x03] = 0x26; - - adlibemu_start_note(0x0e, 0x30, 0x40); - sleep(1); - adlibemu_start_note(0x03, 0x48, 0x40); - sleep(1); - */ -} - - -/* count is # of FRAMES, not bytes. - We assume 16-bit stereo frames (ie 4 bytes) -*/ -static void opl2_poll(sfx_softseq_t *self, byte *dest, int count) { - int16 *ptr = (int16 *)dest; - - if (!ready) - error("synth_mixer(): !ready \n"); - - if (!ptr) - error("synth_mixer(): !buffer \n"); - - YM3812UpdateOne(ym3812, ptr, count); -} - -static Common::Error opl2_init(sfx_softseq_t *self, byte *data_ptr, int data_length, byte *data2_ptr, - int data2_length) { - int i; - - /* load up the patch.003 file, parse out the instruments */ - if (data_length < 1344) { - sciprintf("[sfx:seq:opl2] Invalid patch.003: Expected %d, got %d\n", 1344, data_length); - return Common::kUnknownError; - } - - for (i = 0; i < 48; i++) - make_sbi((adlib_def *)(data_ptr + (28 * i)), adlib_sbi[i]); - - if (data_length > 1344) - for (i = 48; i < 96; i++) - make_sbi((adlib_def *)(data_ptr + 2 + (28 * i)), adlib_sbi[i]); - - if (!(ym3812 = makeAdlibOPL(SAMPLE_RATE))) { - sciprintf("[sfx:seq:opl2] Failure: Emulator init failed!\n"); - return Common::kUnknownError; - } - - ready = 1; - - opl2_allstop(self); - return Common::kNoError; -} - - -static void opl2_exit(sfx_softseq_t *self) { - OPLDestroy(ym3812); - ym3812 = NULL; - - // XXX deregister with pcm layer. -} - -static void opl2_allstop(sfx_softseq_t *self) { - // printf("AdlibEmu: Reset\n"); - if (! ready) - return; - - adlibemu_init_lists(); - - OPLResetChip(ym3812); - - opl_write(0x01, 0x20); - opl_write(0xBD, 0xc0); - -#ifdef DEBUG_ADLIB - printf("ADLIB: reset complete\n"); -#endif - // test_adlib(); -} - -int midi_adlibemu_reverb(short param) { - printf("ADLIB: reverb NYI %04x \n", param); - return 0; -} - -int midi_adlibemu_event(uint8 command, uint8 note, uint8 velocity, uint32 delta) { - uint8 channel, oper; - - channel = command & 0x0f; - oper = command & 0xf0; - - switch (oper) { - case 0x80: - return adlibemu_stop_note(channel, note, velocity); - case 0x90: /* noteon and noteoff */ - return adlibemu_start_note(channel, note, velocity); - case 0xe0: { /* Pitch bend */ - int bend = (note & 0x7f) | ((velocity & 0x7f) << 7); -// printf("Bend to %d\n", bend); - adlibemu_update_pitch(channel, note, bend); - } - case 0xb0: /* CC changes. */ - switch (note) { - case 0x07: - vol[channel] = velocity; - break; - case 0x0a: - pan[channel] = velocity; - break; - case 0x4b: - break; - case 0x7b: { /* all notes off */ - int i = 0; - for (i = 0;i < ADLIB_VOICES;i++) - if (oper_chn[i] == channel) - adlibemu_stop_note(channel, oper_note[i], 0); - break; - } - default: - ; /* XXXX ignore everything else for now */ - } - return 0; - case 0xd0: /* aftertouch */ - /* XXX Aftertouch in the OPL thing? */ - return 0; - default: - printf("ADLIB: Unknown event %02x\n", command); - return 0; - } - - return 0; -} - -int midi_adlibemu_event2(uint8 command, uint8 param, uint32 delta) { - uint8 channel; - uint8 oper; - - channel = command & 0x0f; - oper = command & 0xf0; - switch (oper) { - case 0xc0: /* change instrument */ -#ifdef DEBUG_ADLIB - printf("ADLIB: Selecting instrument %d on channel %d\n", param, channel); -#endif - instr[channel] = param; - return 0; - default: - printf("ADLIB: Unknown event %02x\n", command); - } - - return 0; -} - -static void opl2_volume(sfx_softseq_t *self, int volume) { - uint8 i; - - i = (uint8)volume * 15 / 100; - - adlib_master = i; - -#ifdef DEBUG_ADLIB - printf("ADLIB: master volume set to %d\n", adlib_master); -#endif -} - -static Common::Error opl2_set_option(sfx_softseq_t *self, const char *name, const char *value) { - return Common::kUnknownError; -} - -void opl2_event(sfx_softseq_t *self, byte cmd, int argc, byte *argv) { - if (argc == 1) - midi_adlibemu_event2(cmd, argv[0], 0); - else if (argc == 2) - midi_adlibemu_event(cmd, argv[0], argv[1], 0); -} - -/* the driver struct */ - -sfx_softseq_t sfx_softseq_opl2 = { - "adlibemu", - "0.1", - opl2_set_option, - opl2_init, - opl2_exit, - opl2_volume, - opl2_event, - opl2_poll, - opl2_allstop, - NULL, - 3, /* use patch.003 */ - SFX_SEQ_PATCHFILE_NONE, - 0x4, /* Play flags */ - 0, /* No rhythm channel (9) */ - ADLIB_VOICES, /* # of voices */ - {SAMPLE_RATE, CHANNELS, SFX_PCM_FORMAT_S16_NATIVE} -}; - -} // End of namespace Sci |