trunk/src/mame/drivers/zn.c
| r19948 | r19949 | |
| 652 | 652 | static ADDRESS_MAP_START( qsound_map, AS_PROGRAM, 8, zn_state ) |
| 653 | 653 | AM_RANGE(0x0000, 0x7fff) AM_ROM |
| 654 | 654 | AM_RANGE(0x8000, 0xbfff) AM_ROMBANK("bank10") /* banked (contains music data) */ |
| 655 | | AM_RANGE(0xd000, 0xd002) AM_DEVWRITE_LEGACY("qsound", qsound_w) |
| 655 | AM_RANGE(0xd000, 0xd002) AM_DEVWRITE("qsound", qsound_device, qsound_w) |
| 656 | 656 | AM_RANGE(0xd003, 0xd003) AM_WRITE(qsound_bankswitch_w) |
| 657 | | AM_RANGE(0xd007, 0xd007) AM_DEVREAD_LEGACY("qsound", qsound_r) |
| 657 | AM_RANGE(0xd007, 0xd007) AM_DEVREAD("qsound", qsound_device, qsound_r) |
| 658 | 658 | AM_RANGE(0xf000, 0xffff) AM_RAM |
| 659 | 659 | ADDRESS_MAP_END |
| 660 | 660 | |
| r19948 | r19949 | |
| 666 | 666 | static MACHINE_CONFIG_DERIVED( coh1000c, zn1_1mb_vram ) |
| 667 | 667 | |
| 668 | 668 | MCFG_CPU_ADD( "audiocpu", Z80, 8000000 ) /* 8MHz ?? */ |
| 669 | | MCFG_CPU_PROGRAM_MAP( qsound_map) |
| 670 | | MCFG_CPU_IO_MAP( qsound_portmap) |
| 669 | MCFG_CPU_PROGRAM_MAP( qsound_map ) |
| 670 | MCFG_CPU_IO_MAP( qsound_portmap ) |
| 671 | 671 | MCFG_CPU_PERIODIC_INT_DRIVER(zn_state, qsound_interrupt, 60*4) /* 4 interrupts per frame ?? */ |
| 672 | 672 | |
| 673 | 673 | MCFG_MACHINE_RESET_OVERRIDE(zn_state, coh1000c ) |
| 674 | 674 | |
| 675 | | MCFG_SOUND_ADD( "qsound", QSOUND, QSOUND_CLOCK ) |
| 675 | MCFG_QSOUND_ADD( "qsound", QSOUND_CLOCK ) |
| 676 | 676 | MCFG_SOUND_ROUTE(0, "lspeaker", 1.0) |
| 677 | 677 | MCFG_SOUND_ROUTE(1, "rspeaker", 1.0) |
| 678 | 678 | MACHINE_CONFIG_END |
| r19948 | r19949 | |
| 686 | 686 | |
| 687 | 687 | MCFG_MACHINE_RESET_OVERRIDE(zn_state, coh1000c ) |
| 688 | 688 | |
| 689 | | MCFG_SOUND_ADD( "qsound", QSOUND, QSOUND_CLOCK ) |
| 689 | MCFG_QSOUND_ADD( "qsound", QSOUND_CLOCK ) |
| 690 | 690 | MCFG_SOUND_ROUTE(0, "lspeaker", 1.0) |
| 691 | 691 | MCFG_SOUND_ROUTE(1, "rspeaker", 1.0) |
| 692 | 692 | MACHINE_CONFIG_END |
| r19948 | r19949 | |
| 865 | 865 | |
| 866 | 866 | MCFG_MACHINE_RESET_OVERRIDE(zn_state, coh3002c ) |
| 867 | 867 | |
| 868 | | MCFG_SOUND_ADD( "qsound", QSOUND, QSOUND_CLOCK ) |
| 868 | MCFG_QSOUND_ADD( "qsound", QSOUND_CLOCK ) |
| 869 | 869 | MCFG_SOUND_ROUTE(0, "lspeaker", 1.0) |
| 870 | 870 | MCFG_SOUND_ROUTE(1, "rspeaker", 1.0) |
| 871 | 871 | MACHINE_CONFIG_END |
| r19948 | r19949 | |
| 4613 | 4613 | /* A dummy driver, so that the bios can be debugged, and to serve as */ |
| 4614 | 4614 | /* parent for the coh-1000c.353 file, so that we do not have to include */ |
| 4615 | 4615 | /* it in every zip file */ |
| 4616 | | GAME( 1995, cpzn1, 0, coh1000c, zn, zn_state, coh1000c, ROT0, "Capcom", "ZN1", GAME_IS_BIOS_ROOT ) |
| 4616 | GAME( 1995, cpzn1, 0, coh1000c, zn, zn_state, coh1000c, ROT0, "Capcom", "ZN1", GAME_IS_BIOS_ROOT ) |
| 4617 | 4617 | |
| 4618 | 4618 | GAME( 1995, ts2, cpzn1, coh1000c, zn6b, zn_state, coh1000c, ROT0, "Capcom / Takara", "Battle Arena Toshinden 2 (USA 951124)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) |
| 4619 | 4619 | GAME( 1995, ts2a, ts2, coh1000c, zn6b, zn_state, coh1000c, ROT0, "Capcom / Takara", "Battle Arena Toshinden 2 (USA 951124) Older", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) |
| r19948 | r19949 | |
| 4634 | 4634 | /* A dummy driver, so that the bios can be debugged, and to serve as */ |
| 4635 | 4635 | /* parent for the coh-3002c.353 file, so that we do not have to include */ |
| 4636 | 4636 | /* it in every zip file */ |
| 4637 | | GAME( 1997, cpzn2, 0, coh3002c, zn, zn_state, coh3002c, ROT0, "Capcom", "ZN2", GAME_IS_BIOS_ROOT ) |
| 4637 | GAME( 1997, cpzn2, 0, coh3002c, zn, zn_state, coh3002c, ROT0, "Capcom", "ZN2", GAME_IS_BIOS_ROOT ) |
| 4638 | 4638 | |
| 4639 | 4639 | GAME( 1997, rvschool, cpzn2, coh3002c, zn6b, zn_state, coh3002c, ROT0, "Capcom", "Rival Schools: United By Fate (Euro 971117)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) |
| 4640 | 4640 | GAME( 1997, rvschoolu, rvschool, coh3002c, zn6b, zn_state, coh3002c, ROT0, "Capcom", "Rival Schools: United By Fate (USA 971117)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) |
| r19948 | r19949 | |
| 4684 | 4684 | /* A dummy driver, so that the bios can be debugged, and to serve as */ |
| 4685 | 4685 | /* parent for the coh-1002m.353 file, so that we do not have to include */ |
| 4686 | 4686 | /* it in every zip file */ |
| 4687 | | GAME( 1997, tps, 0, coh1002m, zn, zn_state, coh1002m, ROT0, "Tecmo", "TPS", GAME_IS_BIOS_ROOT ) |
| 4687 | GAME( 1997, tps, 0, coh1002m, zn, zn_state, coh1002m, ROT0, "Tecmo", "TPS", GAME_IS_BIOS_ROOT ) |
| 4688 | 4688 | |
| 4689 | 4689 | GAME( 1997, glpracr2, tps, coh1002m, zn, zn_state, coh1002m, ROT0, "Tecmo", "Gallop Racer 2 (USA)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND | GAME_NOT_WORKING ) |
| 4690 | 4690 | GAME( 1997, glpracr2j, glpracr2, coh1002m, zn, zn_state, coh1002m, ROT0, "Tecmo", "Gallop Racer 2 (Japan)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND | GAME_NOT_WORKING ) |
| r19948 | r19949 | |
| 4717 | 4717 | /* A dummy driver, so that the bios can be debugged, and to serve as */ |
| 4718 | 4718 | /* parent for the coh-1000t.353 file, so that we do not have to include */ |
| 4719 | 4719 | /* it in every zip file */ |
| 4720 | | GAME( 1995, taitofx1, 0, coh1000ta,zn, zn_state, coh1000ta, ROT0, "Taito", "Taito FX1", GAME_IS_BIOS_ROOT ) |
| 4720 | GAME( 1995, taitofx1, 0, coh1000ta,zn, zn_state, coh1000ta, ROT0, "Taito", "Taito FX1", GAME_IS_BIOS_ROOT ) |
| 4721 | 4721 | |
| 4722 | 4722 | GAME( 1995, sfchamp, taitofx1, coh1000ta,zn, zn_state, coh1000ta, ROT0, "Taito", "Super Football Champ (Ver 2.5O)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) |
| 4723 | 4723 | GAME( 1995, sfchampo, sfchamp, coh1000ta,zn, zn_state, coh1000ta, ROT0, "Taito", "Super Football Champ (Ver 2.4O)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) |
| r19948 | r19949 | |
| 4745 | 4745 | /* A dummy driver, so that the bios can be debugged, and to serve as */ |
| 4746 | 4746 | /* parent for the coh-1002e.353 file, so that we do not have to include */ |
| 4747 | 4747 | /* it in every zip file */ |
| 4748 | | GAME( 1997, psarc95, 0, coh1002e, zn, zn_state, coh1002e, ROT0, "Eighting / Raizing", "PS Arcade 95", GAME_IS_BIOS_ROOT ) |
| 4748 | GAME( 1997, psarc95, 0, coh1002e, zn, zn_state, coh1002e, ROT0, "Eighting / Raizing", "PS Arcade 95", GAME_IS_BIOS_ROOT ) |
| 4749 | 4749 | |
| 4750 | 4750 | GAME( 1997, beastrzr, psarc95, coh1002e, zn, zn_state, coh1002e, ROT0, "Eighting / Raizing", "Beastorizer (USA)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) |
| 4751 | 4751 | GAME( 1997, bldyroar, beastrzr, coh1002e, zn, zn_state, coh1002e, ROT0, "Eighting / Raizing", "Bloody Roar (Japan)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) |
trunk/src/emu/sound/qsound.c
| r19948 | r19949 | |
| 34 | 34 | #include "emu.h" |
| 35 | 35 | #include "qsound.h" |
| 36 | 36 | |
| 37 | | /* |
| 38 | | Debug defines |
| 39 | | */ |
| 40 | | #define LOG_WAVE 0 |
| 37 | // Debug defines |
| 38 | #define LOG_WAVE 0 |
| 41 | 39 | #define VERBOSE 0 |
| 42 | 40 | #define LOG(x) do { if (VERBOSE) logerror x; } while (0) |
| 43 | 41 | |
| 44 | | /* 8 bit source ROM samples */ |
| 45 | | typedef INT8 QSOUND_SRC_SAMPLE; |
| 46 | 42 | |
| 43 | // device type definition |
| 44 | const device_type QSOUND = &device_creator<qsound_device>; |
| 47 | 45 | |
| 48 | | #define QSOUND_CLOCKDIV 166 /* Clock divider */ |
| 49 | | #define QSOUND_CHANNELS 16 |
| 50 | | typedef stream_sample_t QSOUND_SAMPLE; |
| 51 | 46 | |
| 52 | | struct QSOUND_CHANNEL |
| 53 | | { |
| 54 | | INT32 bank; /* bank (x16) */ |
| 55 | | INT32 address; /* start address */ |
| 56 | | INT32 pitch; /* pitch */ |
| 57 | | INT32 reg3; /* unknown (always 0x8000) */ |
| 58 | | INT32 loop; /* loop address */ |
| 59 | | INT32 end; /* end address */ |
| 60 | | INT32 vol; /* master volume */ |
| 61 | | INT32 pan; /* Pan value */ |
| 62 | | INT32 reg9; /* unknown */ |
| 47 | //************************************************************************** |
| 48 | // LIVE DEVICE |
| 49 | //************************************************************************** |
| 63 | 50 | |
| 64 | | /* Work variables */ |
| 65 | | INT32 key; /* Key on / key off */ |
| 51 | //------------------------------------------------- |
| 52 | // qsound_device - constructor |
| 53 | //------------------------------------------------- |
| 66 | 54 | |
| 67 | | INT32 lvol; /* left volume */ |
| 68 | | INT32 rvol; /* right volume */ |
| 69 | | INT32 lastdt; /* last sample value */ |
| 70 | | INT32 offset; /* current offset counter */ |
| 71 | | }; |
| 72 | | |
| 73 | | struct qsound_state |
| 55 | qsound_device::qsound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 56 | : device_t(mconfig, QSOUND, "Q-Sound", tag, owner, clock), |
| 57 | device_sound_interface(mconfig, *this), |
| 58 | m_data(0), |
| 59 | m_stream(NULL), |
| 60 | m_sample_rom_length(0), |
| 61 | m_sample_rom(NULL), |
| 62 | m_frq_ratio(0.0f), |
| 63 | m_fpRawDataL(NULL), |
| 64 | m_fpRawDataR(NULL) |
| 74 | 65 | { |
| 75 | | /* Private variables */ |
| 76 | | sound_stream * stream; /* Audio stream */ |
| 77 | | struct QSOUND_CHANNEL channel[QSOUND_CHANNELS]; |
| 78 | | int data; /* register latch data */ |
| 79 | | QSOUND_SRC_SAMPLE *sample_rom; /* Q sound sample ROM */ |
| 80 | | UINT32 sample_rom_length; |
| 81 | | |
| 82 | | int pan_table[33]; /* Pan volume table */ |
| 83 | | float frq_ratio; /* Frequency ratio */ |
| 84 | | |
| 85 | | FILE *fpRawDataL; |
| 86 | | FILE *fpRawDataR; |
| 87 | | }; |
| 88 | | |
| 89 | | INLINE qsound_state *get_safe_token(device_t *device) |
| 90 | | { |
| 91 | | assert(device != NULL); |
| 92 | | assert(device->type() == QSOUND); |
| 93 | | return (qsound_state *)downcast<qsound_device *>(device)->token(); |
| 94 | 66 | } |
| 95 | 67 | |
| 96 | 68 | |
| 97 | | /* Function prototypes */ |
| 98 | | static STREAM_UPDATE( qsound_update ); |
| 99 | | static void qsound_set_command(qsound_state *chip, int data, int value); |
| 69 | //------------------------------------------------- |
| 70 | // device_start - device-specific startup |
| 71 | //------------------------------------------------- |
| 100 | 72 | |
| 101 | | static DEVICE_START( qsound ) |
| 73 | void qsound_device::device_start() |
| 102 | 74 | { |
| 103 | | qsound_state *chip = get_safe_token(device); |
| 104 | 75 | int i; |
| 105 | 76 | |
| 106 | | chip->sample_rom = (QSOUND_SRC_SAMPLE *)*device->region(); |
| 107 | | chip->sample_rom_length = device->region()->bytes(); |
| 77 | m_sample_rom = (QSOUND_SRC_SAMPLE *)*region(); |
| 78 | m_sample_rom_length = region()->bytes(); |
| 108 | 79 | |
| 109 | | memset(chip->channel, 0, sizeof(chip->channel)); |
| 80 | memset(m_channel, 0, sizeof(m_channel)); |
| 110 | 81 | |
| 111 | | chip->frq_ratio = 16.0; |
| 82 | m_frq_ratio = 16.0; |
| 112 | 83 | |
| 113 | 84 | /* Create pan table */ |
| 114 | 85 | for (i=0; i<33; i++) |
| 115 | 86 | { |
| 116 | | chip->pan_table[i]=(int)((256/sqrt(32.0)) * sqrt((double)i)); |
| 87 | m_pan_table[i]=(int)((256/sqrt(32.0)) * sqrt((double)i)); |
| 117 | 88 | } |
| 118 | 89 | |
| 119 | 90 | LOG(("Pan table\n")); |
| 120 | 91 | for (i=0; i<33; i++) |
| 121 | | LOG(("%02x ", chip->pan_table[i])); |
| 92 | LOG(("%02x ", m_pan_table[i])); |
| 122 | 93 | |
| 123 | | { |
| 124 | | /* Allocate stream */ |
| 125 | | chip->stream = device->machine().sound().stream_alloc( |
| 126 | | *device, 0, 2, |
| 127 | | device->clock() / QSOUND_CLOCKDIV, |
| 128 | | chip, |
| 129 | | qsound_update ); |
| 130 | | } |
| 94 | /* Allocate stream */ |
| 95 | m_stream = stream_alloc(0, 2, clock() / QSOUND_CLOCKDIV); |
| 131 | 96 | |
| 132 | 97 | if (LOG_WAVE) |
| 133 | 98 | { |
| 134 | | chip->fpRawDataR=fopen("qsoundr.raw", "w+b"); |
| 135 | | chip->fpRawDataL=fopen("qsoundl.raw", "w+b"); |
| 99 | m_fpRawDataR=fopen("qsoundr.raw", "w+b"); |
| 100 | m_fpRawDataL=fopen("qsoundl.raw", "w+b"); |
| 136 | 101 | } |
| 137 | 102 | |
| 138 | 103 | /* state save */ |
| 139 | 104 | for (i=0; i<QSOUND_CHANNELS; i++) |
| 140 | 105 | { |
| 141 | | device->save_item(NAME(chip->channel[i].bank), i); |
| 142 | | device->save_item(NAME(chip->channel[i].address), i); |
| 143 | | device->save_item(NAME(chip->channel[i].pitch), i); |
| 144 | | device->save_item(NAME(chip->channel[i].loop), i); |
| 145 | | device->save_item(NAME(chip->channel[i].end), i); |
| 146 | | device->save_item(NAME(chip->channel[i].vol), i); |
| 147 | | device->save_item(NAME(chip->channel[i].pan), i); |
| 148 | | device->save_item(NAME(chip->channel[i].key), i); |
| 149 | | device->save_item(NAME(chip->channel[i].lvol), i); |
| 150 | | device->save_item(NAME(chip->channel[i].rvol), i); |
| 151 | | device->save_item(NAME(chip->channel[i].lastdt), i); |
| 152 | | device->save_item(NAME(chip->channel[i].offset), i); |
| 106 | save_item(NAME(m_channel[i].bank), i); |
| 107 | save_item(NAME(m_channel[i].address), i); |
| 108 | save_item(NAME(m_channel[i].pitch), i); |
| 109 | save_item(NAME(m_channel[i].loop), i); |
| 110 | save_item(NAME(m_channel[i].end), i); |
| 111 | save_item(NAME(m_channel[i].vol), i); |
| 112 | save_item(NAME(m_channel[i].pan), i); |
| 113 | save_item(NAME(m_channel[i].key), i); |
| 114 | save_item(NAME(m_channel[i].lvol), i); |
| 115 | save_item(NAME(m_channel[i].rvol), i); |
| 116 | save_item(NAME(m_channel[i].lastdt), i); |
| 117 | save_item(NAME(m_channel[i].offset), i); |
| 153 | 118 | } |
| 154 | 119 | } |
| 155 | 120 | |
| 156 | | static DEVICE_STOP( qsound ) |
| 121 | //------------------------------------------------- |
| 122 | // device_stop - device-specific stop |
| 123 | //------------------------------------------------- |
| 124 | |
| 125 | void qsound_device::device_stop() |
| 157 | 126 | { |
| 158 | | qsound_state *chip = get_safe_token(device); |
| 159 | | if (chip->fpRawDataR) |
| 127 | if (m_fpRawDataR) |
| 160 | 128 | { |
| 161 | | fclose(chip->fpRawDataR); |
| 129 | fclose(m_fpRawDataR); |
| 162 | 130 | } |
| 163 | | chip->fpRawDataR = NULL; |
| 164 | | if (chip->fpRawDataL) |
| 131 | m_fpRawDataR = NULL; |
| 132 | if (m_fpRawDataL) |
| 165 | 133 | { |
| 166 | | fclose(chip->fpRawDataL); |
| 134 | fclose(m_fpRawDataL); |
| 167 | 135 | } |
| 168 | | chip->fpRawDataL = NULL; |
| 136 | m_fpRawDataL = NULL; |
| 169 | 137 | } |
| 170 | 138 | |
| 171 | | WRITE8_DEVICE_HANDLER( qsound_w ) |
| 139 | |
| 140 | //------------------------------------------------- |
| 141 | // sound_stream_update - handle a stream update |
| 142 | //------------------------------------------------- |
| 143 | |
| 144 | void qsound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) |
| 172 | 145 | { |
| 173 | | qsound_state *chip = get_safe_token(device); |
| 146 | int i,j; |
| 147 | int rvol, lvol, count; |
| 148 | struct QSOUND_CHANNEL *pC=&m_channel[0]; |
| 149 | stream_sample_t *datap[2]; |
| 150 | |
| 151 | datap[0] = outputs[0]; |
| 152 | datap[1] = outputs[1]; |
| 153 | memset( datap[0], 0x00, samples * sizeof(*datap[0]) ); |
| 154 | memset( datap[1], 0x00, samples * sizeof(*datap[1]) ); |
| 155 | |
| 156 | for (i=0; i<QSOUND_CHANNELS; i++) |
| 157 | { |
| 158 | if (pC->key) |
| 159 | { |
| 160 | QSOUND_SAMPLE *pOutL=datap[0]; |
| 161 | QSOUND_SAMPLE *pOutR=datap[1]; |
| 162 | rvol=(pC->rvol*pC->vol)>>8; |
| 163 | lvol=(pC->lvol*pC->vol)>>8; |
| 164 | |
| 165 | for (j=samples-1; j>=0; j--) |
| 166 | { |
| 167 | count=(pC->offset)>>16; |
| 168 | pC->offset &= 0xffff; |
| 169 | if (count) |
| 170 | { |
| 171 | pC->address += count; |
| 172 | if (pC->address >= pC->end) |
| 173 | { |
| 174 | if (!pC->loop) |
| 175 | { |
| 176 | /* Reached the end of a non-looped sample */ |
| 177 | pC->key=0; |
| 178 | break; |
| 179 | } |
| 180 | /* Reached the end, restart the loop */ |
| 181 | pC->address = (pC->end - pC->loop) & 0xffff; |
| 182 | } |
| 183 | pC->lastdt=m_sample_rom[(pC->bank+pC->address)%(m_sample_rom_length)]; |
| 184 | } |
| 185 | |
| 186 | (*pOutL) += ((pC->lastdt * lvol) >> 6); |
| 187 | (*pOutR) += ((pC->lastdt * rvol) >> 6); |
| 188 | pOutL++; |
| 189 | pOutR++; |
| 190 | pC->offset += pC->pitch; |
| 191 | } |
| 192 | } |
| 193 | pC++; |
| 194 | } |
| 195 | |
| 196 | if (m_fpRawDataL) |
| 197 | fwrite(datap[0], samples*sizeof(QSOUND_SAMPLE), 1, m_fpRawDataL); |
| 198 | if (m_fpRawDataR) |
| 199 | fwrite(datap[1], samples*sizeof(QSOUND_SAMPLE), 1, m_fpRawDataR); |
| 200 | } |
| 201 | |
| 202 | |
| 203 | WRITE8_MEMBER( qsound_device::qsound_w ) |
| 204 | { |
| 174 | 205 | switch (offset) |
| 175 | 206 | { |
| 176 | 207 | case 0: |
| 177 | | chip->data=(chip->data&0xff)|(data<<8); |
| 208 | m_data=(m_data&0xff)|(data<<8); |
| 178 | 209 | break; |
| 179 | 210 | |
| 180 | 211 | case 1: |
| 181 | | chip->data=(chip->data&0xff00)|data; |
| 212 | m_data=(m_data&0xff00)|data; |
| 182 | 213 | break; |
| 183 | 214 | |
| 184 | 215 | case 2: |
| 185 | | qsound_set_command(chip, data, chip->data); |
| 216 | qsound_set_command(data, m_data); |
| 186 | 217 | break; |
| 187 | 218 | |
| 188 | 219 | default: |
| 189 | | logerror("%s: unexpected qsound write to offset %d == %02X\n", device->machine().describe_context(), offset, data); |
| 220 | logerror("%s: unexpected qsound write to offset %d == %02X\n", machine().describe_context(), offset, data); |
| 190 | 221 | break; |
| 191 | 222 | } |
| 192 | 223 | } |
| 193 | 224 | |
| 194 | | READ8_DEVICE_HANDLER( qsound_r ) |
| 225 | |
| 226 | READ8_MEMBER( qsound_device::qsound_r ) |
| 195 | 227 | { |
| 196 | 228 | /* Port ready bit (0x80 if ready) */ |
| 197 | 229 | return 0x80; |
| 198 | 230 | } |
| 199 | 231 | |
| 200 | | static void qsound_set_command(qsound_state *chip, int data, int value) |
| 232 | |
| 233 | void qsound_device::qsound_set_command(int data, int value) |
| 201 | 234 | { |
| 202 | 235 | int ch=0,reg=0; |
| 203 | 236 | if (data < 0x80) |
| r19948 | r19949 | |
| 232 | 265 | { |
| 233 | 266 | case 0: /* Bank */ |
| 234 | 267 | ch=(ch+1)&0x0f; /* strange ... */ |
| 235 | | chip->channel[ch].bank=(value&0x7f)<<16; |
| 268 | m_channel[ch].bank=(value&0x7f)<<16; |
| 236 | 269 | #ifdef MAME_DEBUG |
| 237 | 270 | if (!(value & 0x8000)) |
| 238 | 271 | popmessage("Register3=%04x",value); |
| r19948 | r19949 | |
| 240 | 273 | |
| 241 | 274 | break; |
| 242 | 275 | case 1: /* start */ |
| 243 | | chip->channel[ch].address=value; |
| 276 | m_channel[ch].address=value; |
| 244 | 277 | break; |
| 245 | 278 | case 2: /* pitch */ |
| 246 | | chip->channel[ch].pitch=value * 16; |
| 279 | m_channel[ch].pitch=value * 16; |
| 247 | 280 | if (!value) |
| 248 | 281 | { |
| 249 | 282 | /* Key off */ |
| 250 | | chip->channel[ch].key=0; |
| 283 | m_channel[ch].key=0; |
| 251 | 284 | } |
| 252 | 285 | break; |
| 253 | 286 | case 3: /* unknown */ |
| 254 | | chip->channel[ch].reg3=value; |
| 287 | m_channel[ch].reg3=value; |
| 255 | 288 | #ifdef MAME_DEBUG |
| 256 | 289 | if (value != 0x8000) |
| 257 | 290 | popmessage("Register3=%04x",value); |
| 258 | 291 | #endif |
| 259 | 292 | break; |
| 260 | 293 | case 4: /* loop offset */ |
| 261 | | chip->channel[ch].loop=value; |
| 294 | m_channel[ch].loop=value; |
| 262 | 295 | break; |
| 263 | 296 | case 5: /* end */ |
| 264 | | chip->channel[ch].end=value; |
| 297 | m_channel[ch].end=value; |
| 265 | 298 | break; |
| 266 | 299 | case 6: /* master volume */ |
| 267 | 300 | if (value==0) |
| 268 | 301 | { |
| 269 | 302 | /* Key off */ |
| 270 | | chip->channel[ch].key=0; |
| 303 | m_channel[ch].key=0; |
| 271 | 304 | } |
| 272 | | else if (chip->channel[ch].key==0) |
| 305 | else if (m_channel[ch].key==0) |
| 273 | 306 | { |
| 274 | 307 | /* Key on */ |
| 275 | | chip->channel[ch].key=1; |
| 276 | | chip->channel[ch].offset=0; |
| 277 | | chip->channel[ch].lastdt=0; |
| 308 | m_channel[ch].key=1; |
| 309 | m_channel[ch].offset=0; |
| 310 | m_channel[ch].lastdt=0; |
| 278 | 311 | } |
| 279 | | chip->channel[ch].vol=value; |
| 312 | m_channel[ch].vol=value; |
| 280 | 313 | break; |
| 281 | 314 | |
| 282 | 315 | case 7: /* unused */ |
| r19948 | r19949 | |
| 292 | 325 | { |
| 293 | 326 | pandata=32; |
| 294 | 327 | } |
| 295 | | chip->channel[ch].rvol=chip->pan_table[pandata]; |
| 296 | | chip->channel[ch].lvol=chip->pan_table[32-pandata]; |
| 297 | | chip->channel[ch].pan = value; |
| 328 | m_channel[ch].rvol=m_pan_table[pandata]; |
| 329 | m_channel[ch].lvol=m_pan_table[32-pandata]; |
| 330 | m_channel[ch].pan = value; |
| 298 | 331 | } |
| 299 | 332 | break; |
| 300 | 333 | case 9: |
| 301 | | chip->channel[ch].reg9=value; |
| 334 | m_channel[ch].reg9=value; |
| 302 | 335 | /* |
| 303 | 336 | #ifdef MAME_DEBUG |
| 304 | 337 | popmessage("QSOUND REG 9=%04x",value); |
| r19948 | r19949 | |
| 308 | 341 | } |
| 309 | 342 | LOG(("QSOUND WRITE %02x CH%02d-R%02d =%04x\n", data, ch, reg, value)); |
| 310 | 343 | } |
| 311 | | |
| 312 | | |
| 313 | | static STREAM_UPDATE( qsound_update ) |
| 314 | | { |
| 315 | | qsound_state *chip = (qsound_state *)param; |
| 316 | | int i,j; |
| 317 | | int rvol, lvol, count; |
| 318 | | struct QSOUND_CHANNEL *pC=&chip->channel[0]; |
| 319 | | stream_sample_t *datap[2]; |
| 320 | | |
| 321 | | datap[0] = outputs[0]; |
| 322 | | datap[1] = outputs[1]; |
| 323 | | memset( datap[0], 0x00, samples * sizeof(*datap[0]) ); |
| 324 | | memset( datap[1], 0x00, samples * sizeof(*datap[1]) ); |
| 325 | | |
| 326 | | for (i=0; i<QSOUND_CHANNELS; i++) |
| 327 | | { |
| 328 | | if (pC->key) |
| 329 | | { |
| 330 | | QSOUND_SAMPLE *pOutL=datap[0]; |
| 331 | | QSOUND_SAMPLE *pOutR=datap[1]; |
| 332 | | rvol=(pC->rvol*pC->vol)>>8; |
| 333 | | lvol=(pC->lvol*pC->vol)>>8; |
| 334 | | |
| 335 | | for (j=samples-1; j>=0; j--) |
| 336 | | { |
| 337 | | count=(pC->offset)>>16; |
| 338 | | pC->offset &= 0xffff; |
| 339 | | if (count) |
| 340 | | { |
| 341 | | pC->address += count; |
| 342 | | if (pC->address >= pC->end) |
| 343 | | { |
| 344 | | if (!pC->loop) |
| 345 | | { |
| 346 | | /* Reached the end of a non-looped sample */ |
| 347 | | pC->key=0; |
| 348 | | break; |
| 349 | | } |
| 350 | | /* Reached the end, restart the loop */ |
| 351 | | pC->address = (pC->end - pC->loop) & 0xffff; |
| 352 | | } |
| 353 | | pC->lastdt=chip->sample_rom[(pC->bank+pC->address)%(chip->sample_rom_length)]; |
| 354 | | } |
| 355 | | |
| 356 | | (*pOutL) += ((pC->lastdt * lvol) >> 6); |
| 357 | | (*pOutR) += ((pC->lastdt * rvol) >> 6); |
| 358 | | pOutL++; |
| 359 | | pOutR++; |
| 360 | | pC->offset += pC->pitch; |
| 361 | | } |
| 362 | | } |
| 363 | | pC++; |
| 364 | | } |
| 365 | | |
| 366 | | if (chip->fpRawDataL) |
| 367 | | fwrite(datap[0], samples*sizeof(QSOUND_SAMPLE), 1, chip->fpRawDataL); |
| 368 | | if (chip->fpRawDataR) |
| 369 | | fwrite(datap[1], samples*sizeof(QSOUND_SAMPLE), 1, chip->fpRawDataR); |
| 370 | | } |
| 371 | | |
| 372 | | const device_type QSOUND = &device_creator<qsound_device>; |
| 373 | | |
| 374 | | qsound_device::qsound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 375 | | : device_t(mconfig, QSOUND, "Q-Sound", tag, owner, clock), |
| 376 | | device_sound_interface(mconfig, *this) |
| 377 | | { |
| 378 | | m_token = global_alloc_clear(qsound_state); |
| 379 | | } |
| 380 | | |
| 381 | | //------------------------------------------------- |
| 382 | | // device_config_complete - perform any |
| 383 | | // operations now that the configuration is |
| 384 | | // complete |
| 385 | | //------------------------------------------------- |
| 386 | | |
| 387 | | void qsound_device::device_config_complete() |
| 388 | | { |
| 389 | | } |
| 390 | | |
| 391 | | //------------------------------------------------- |
| 392 | | // device_start - device-specific startup |
| 393 | | //------------------------------------------------- |
| 394 | | |
| 395 | | void qsound_device::device_start() |
| 396 | | { |
| 397 | | DEVICE_START_NAME( qsound )(this); |
| 398 | | } |
| 399 | | |
| 400 | | //------------------------------------------------- |
| 401 | | // device_stop - device-specific stop |
| 402 | | //------------------------------------------------- |
| 403 | | |
| 404 | | void qsound_device::device_stop() |
| 405 | | { |
| 406 | | DEVICE_STOP_NAME( qsound )(this); |
| 407 | | } |
| 408 | | |
| 409 | | //------------------------------------------------- |
| 410 | | // sound_stream_update - handle a stream update |
| 411 | | //------------------------------------------------- |
| 412 | | |
| 413 | | void qsound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) |
| 414 | | { |
| 415 | | // should never get here |
| 416 | | fatalerror("sound_stream_update called; not applicable to legacy sound devices\n"); |
| 417 | | } |
| 418 | | |
| 419 | | |
trunk/src/emu/sound/qsound.h
| r19948 | r19949 | |
| 9 | 9 | #ifndef __QSOUND_H__ |
| 10 | 10 | #define __QSOUND_H__ |
| 11 | 11 | |
| 12 | | #include "devlegcy.h" |
| 12 | #define QSOUND_CLOCK 4000000 /* default 4MHz clock */ |
| 13 | 13 | |
| 14 | | #define QSOUND_CLOCK 4000000 /* default 4MHz clock */ |
| 14 | #define QSOUND_CLOCKDIV 166 /* Clock divider */ |
| 15 | #define QSOUND_CHANNELS 16 |
| 16 | typedef INT8 QSOUND_SRC_SAMPLE; /* 8 bit source ROM samples */ |
| 17 | typedef stream_sample_t QSOUND_SAMPLE; |
| 15 | 18 | |
| 16 | | DECLARE_WRITE8_DEVICE_HANDLER( qsound_w ); |
| 17 | | DECLARE_READ8_DEVICE_HANDLER( qsound_r ); |
| 18 | 19 | |
| 20 | //************************************************************************** |
| 21 | // INTERFACE CONFIGURATION MACROS |
| 22 | //************************************************************************** |
| 23 | |
| 24 | #define MCFG_QSOUND_ADD(_tag, _clock) \ |
| 25 | MCFG_DEVICE_ADD(_tag, QSOUND, _clock) \ |
| 26 | |
| 27 | #define MCFG_QSOUND_REPLACE(_tag, _clock) \ |
| 28 | MCFG_DEVICE_REPLACE(_tag, QSOUND, _clock) \ |
| 29 | |
| 30 | |
| 31 | |
| 32 | //************************************************************************** |
| 33 | // TYPE DEFINITIONS |
| 34 | //************************************************************************** |
| 35 | |
| 36 | struct QSOUND_CHANNEL |
| 37 | { |
| 38 | INT32 bank; // bank (x16) |
| 39 | INT32 address; // start address |
| 40 | INT32 pitch; // pitch |
| 41 | INT32 reg3; // unknown (always 0x8000) |
| 42 | INT32 loop; // loop address |
| 43 | INT32 end; // end address |
| 44 | INT32 vol; // master volume |
| 45 | INT32 pan; // Pan value |
| 46 | INT32 reg9; // unknown |
| 47 | |
| 48 | /* Work variables */ |
| 49 | INT32 key; // Key on / key off |
| 50 | INT32 lvol; // left volume |
| 51 | INT32 rvol; // right volume |
| 52 | INT32 lastdt; // last sample value |
| 53 | INT32 offset; // current offset counter |
| 54 | }; |
| 55 | |
| 56 | |
| 57 | // ======================> qsound_device |
| 58 | |
| 19 | 59 | class qsound_device : public device_t, |
| 20 | | public device_sound_interface |
| 60 | public device_sound_interface |
| 21 | 61 | { |
| 22 | 62 | public: |
| 23 | 63 | qsound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 24 | | ~qsound_device() { global_free(m_token); } |
| 64 | ~qsound_device() { } |
| 25 | 65 | |
| 26 | | // access to legacy token |
| 27 | | void *token() const { assert(m_token != NULL); return m_token; } |
| 28 | 66 | protected: |
| 29 | 67 | // device-level overrides |
| 30 | | virtual void device_config_complete(); |
| 31 | 68 | virtual void device_start(); |
| 32 | 69 | virtual void device_stop(); |
| 33 | 70 | |
| 34 | 71 | // sound stream update overrides |
| 35 | 72 | virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); |
| 73 | |
| 74 | public: |
| 75 | DECLARE_WRITE8_MEMBER( qsound_w ); |
| 76 | DECLARE_READ8_MEMBER( qsound_r ); |
| 77 | |
| 36 | 78 | private: |
| 37 | | // internal state |
| 38 | | void *m_token; |
| 79 | void qsound_set_command(int data, int value); |
| 80 | |
| 81 | private: |
| 82 | int m_data; // register latch data |
| 83 | sound_stream *m_stream; // Audio stream |
| 84 | QSOUND_CHANNEL m_channel[QSOUND_CHANNELS]; |
| 85 | UINT32 m_sample_rom_length; |
| 86 | QSOUND_SRC_SAMPLE *m_sample_rom; // Q sound sample ROM |
| 87 | |
| 88 | int m_pan_table[33]; // Pan volume table |
| 89 | float m_frq_ratio; // Frequency ratio |
| 90 | |
| 91 | FILE *m_fpRawDataL; |
| 92 | FILE *m_fpRawDataR; |
| 39 | 93 | }; |
| 40 | 94 | |
| 41 | 95 | extern const device_type QSOUND; |