Ticket #9109: pce_player.patch

File pce_player.patch, 29.6 KB (added by SF/tobigun, 14 years ago)

PC-Engine sound player (version 2)

  • engines/scumm/player_pce.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/engines/scumm/player_nes.h $
     22 * $Id: player_nes.h 27024 2007-05-30 21:56:52Z fingolfin $
     23 *
     24 */
     25
     26/*
     27 * The PSG_HuC6280 class is based on the HuC6280 sound chip emulator
     28 * by Charles MacDonald (E-mail: cgfm2@hotmail.com, WWW: http://cgfm2.emuviews.com)
     29 * The implementation used here was taken from MESS (http://www.mess.org/)
     30 * the Multiple Emulator Super System (sound/c6280.c).
     31 * LFO and noise channel support have been removed (not used by Loom PCE).
     32 */
     33
     34#include <math.h>
     35#include "player_pce.h"
     36
     37namespace Scumm {
     38
     39// CPU and PSG use the same base clock but with a different divider
     40const double MASTER_CLOCK = 21477270.0;      // ~21.48 MHz
     41const double CPU_CLOCK = MASTER_CLOCK / 3;   // ~7.16 MHz
     42const double PSG_CLOCK = MASTER_CLOCK / 6;   // ~3.58 MHz
     43const double TIMER_CLOCK = CPU_CLOCK / 1024; // ~6.9 kHz
     44
     45// The PSG update routine is originally triggered by the timer IRQ (not by VSYNC)
     46// approx. 120 times per second (TIML=0x39). But as just every second call is used
     47// to update the PSG we will call the update routine approx. 60 times per second.
     48const double UPDATE_FREQ = TIMER_CLOCK / (57 + 1) / 2; // ~60 Hz
     49
     50// $AFA5
     51static const byte wave_table[7][32] = {
     52        { // sine
     53        0x10, 0x19, 0x1C, 0x1D, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1D, 0x1C, 0x19,
     54        0x10, 0x05, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x05,
     55        }, { // mw-shaped
     56        0x10, 0x1C, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, 0x1E, 0x1C, 0x1E, 0x1F, 0x1F, 0x1E, 0x1E, 0x1D, 0x1C,
     57        0x10, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03,
     58        }, { // square
     59        0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
     60        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
     61        }, { // triangle
     62        0x10, 0x0C, 0x08, 0x04, 0x01, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x1F, 0x1C, 0x18, 0x14,
     63        0x10, 0x0C, 0x08, 0x04, 0x01, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x1F, 0x1C, 0x18, 0x14,
     64        }, { // saw-tooth
     65        0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
     66        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
     67        }, { // sigmoid
     68        0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x1F, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19,
     69        0x08, 0x06, 0x05, 0x03, 0x02, 0x01, 0x00, 0x00, 0x0F, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x16,
     70        }, { // MW-shaped
     71        0x1F, 0x1E, 0x1D, 0x1D, 0x1C, 0x1A, 0x17, 0x0F, 0x0F, 0x17, 0x1A, 0x1C, 0x1D, 0x1D, 0x1E, 0x1F,
     72        0x00, 0x01, 0x02, 0x02, 0x03, 0x05, 0x08, 0x0F, 0x0F, 0x08, 0x05, 0x03, 0x02, 0x02, 0x01, 0x00
     73        }
     74};
     75
     76// AEBC
     77static const int control_offsets[14] = {
     78        0, 7, 20, 33, 46, 56, 75, 88, 116, 126, 136, 152, 165, 181
     79};
     80
     81// AED8
     82static const byte control_data[205] = {
     83        /*  0*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0xFF,
     84        /*  7*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x01, 0x00, 0xF0, 0x3A, 0x00, 0xFD, 0xFF,
     85        /* 20*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x01, 0x00, 0xF0, 0x1D, 0x00, 0xF8, 0xFF,
     86        /* 33*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x02, 0x00, 0xF0, 0x1E, 0x00, 0xFC, 0xFF,
     87        /* 46*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x07, 0x00, 0xE0, 0xFF,
     88        /* 56*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x01, 0x00, 0xD8, 0xF0, 0x00, 0xD8, 0x01, 0x00, 0x00, 0x04, 0x00, 0xF0, 0xFF,
     89        /* 75*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x03, 0x00, 0xF8, 0x6E, 0x00, 0xFF, 0xFF,
     90        /* 88*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x08, 0x00, 0xF0, 0xF0, 0x00, 0xD0, 0x01, 0x00, 0x00, 0x05, 0x00, 0xF0, 0xF0, 0x00, 0xB8, 0xE6, 0x80, 0xFF, 0xE6, 0x80, 0xFF, 0xFF,
     91        /*116*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x05, 0x00, 0xD0, 0xFF,
     92        /*126*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x04, 0x00, 0xF8, 0xFF,
     93        /*136*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x03, 0x00, 0xF4, 0xE6, 0xC0, 0xFF, 0xE6, 0xC0, 0xFF, 0xFF,
     94        /*152*/ 0xF0, 0x00, 0xD0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x10, 0x0E, 0x00, 0xFE, 0xFF,
     95        /*165*/ 0xF0, 0x00, 0xA8, 0x01, 0x00, 0x00, 0x18, 0x00, 0x02, 0xE6, 0x80, 0xFE, 0xE6, 0xC0, 0xFF, 0xFF,
     96        /*181*/ 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x02, 0x00, 0xF8, 0x02, 0x00, 0x00, 0x02, 0x00, 0xF0, 0x01, 0x00, 0xF8, 0x02, 0x00, 0x08, 0xF1, 0x99, 0xAF
     97};
     98
     99static const uint16 lookup_table[87] = {
     100        0x0D40, 0x0C80, 0x0BC0, 0x0B20, 0x0A80, 0x09E0, 0x0940, 0x08C0,
     101        0x0840, 0x07E0, 0x0760, 0x0700, 0x06A0, 0x0640, 0x05E0, 0x0590,
     102        0x0540, 0x04F0, 0x04A0, 0x0460, 0x0420, 0x03F0, 0x03B0, 0x0380,
     103        0x0350, 0x0320, 0x02F0, 0x02C8, 0x02A0, 0x0278, 0x0250, 0x0230,
     104        0x0210, 0x01F8, 0x01D8, 0x01C0, 0x01A8, 0x0190, 0x0178, 0x0164,
     105        0x0150, 0x013C, 0x0128, 0x0118, 0x0108, 0x00FC, 0x00EC, 0x00E0,
     106        0x00D4, 0x00C8, 0x00BC, 0x00B2, 0x00A8, 0x009E, 0x0094, 0x008C,
     107        0x0084, 0x007E, 0x0076, 0x0070, 0x006A, 0x0064, 0x005E, 0x0059,
     108        0x0054, 0x004F, 0x004A, 0x0046, 0x0042, 0x003F, 0x003B, 0x0038,
     109        0x0035, 0x0032, 0x0030, 0x002D, 0x002A, 0x0028, 0x0026, 0x0024,
     110        0x0022, 0x0020, 0x001E, 0x001C, 0x001B, 0x8E82, 0xB500
     111};
     112
     113// B27B
     114static const uint16 freq_offset[3] = {
     115        0, 2, 9
     116};
     117
     118static const uint16 freq_table[] = {
     119        0x0000, 0x0800,
     120        0xFFB0, 0xFFD1, 0xFFE8, 0xFFF1, 0x0005, 0x0000, 0x0800,
     121        0xFF9C, 0xFFD8, 0x0000, 0x000F, 0x0005, 0x0000, 0x0800
     122};
     123
     124static const int sound_table[13] = {
     125        0, 2, 3, 4, 5, 6, 7, 8, 9, 11, 1, 10, 11
     126};
     127
     128// 0xAE12
     129// Note:
     130// - offsets relative to data_table
     131// - byte one of each sound was always 0x3F (= use all channels) -> removed from table
     132static const uint16 sounds[13][6] = {
     133        { 481, 481, 481, 481, 481, 481 },
     134        { 395, 408, 467, 480, 480, 480 },
     135        {  85,  96, 109, 109, 109, 109 },
     136        { 110, 121, 134, 134, 134, 134 },
     137        { 135, 146, 159, 159, 159, 159 },
     138        { 160, 171, 184, 184, 184, 184 },
     139        { 185, 196, 209, 209, 209, 209 },
     140        { 210, 221, 234, 234, 234, 234 },
     141        { 235, 246, 259, 259, 259, 259 },
     142        { 260, 271, 284, 284, 284, 284 },
     143        { 285, 298, 311, 324, 335, 348 },
     144        { 349, 360, 361, 362, 373, 384 },
     145        {   0,  84,  84,  84,  84,  84 } // unused
     146};
     147
     148// 0xB2A1
     149static const byte data_table[482] = {
     150        /*  0*/ 0xE2, 0x0A, 0xE1, 0x0D, 0xE6, 0xED, 0xE0, 0x0F, 0xE2, 0x00, 0xE1, 0x00,
     151                0xF2, 0xF2, 0xB2, 0xE1, 0x01, 0xF2, 0xF2, 0xB2, 0xE1, 0x02, 0xF2, 0xF2,
     152                        0xB2, 0xE1, 0x03, 0xF2, 0xF2, 0xB2, 0xE1, 0x04, 0xF2, 0xF2, 0xB2, 0xE1,
     153                        0x05, 0xF2, 0xF2, 0xB2, 0xE1, 0x06, 0xF2, 0xF2, 0xB2, 0xE1, 0x07, 0xF2,
     154                        0xF2, 0xB2, 0xE1, 0x08, 0xF2, 0xF2, 0xB2, 0xE1, 0x09, 0xF2, 0xF2, 0xB2,
     155                        0xE1, 0x0A, 0xF2, 0xF2, 0xB2, 0xE1, 0x0B, 0xF2, 0xF2, 0xB2, 0xE1, 0x0C,
     156                        0xF2, 0xF2, 0xB2, 0xE1, 0x0D, 0xF2, 0xF2, 0xB2, 0xFF, 0xD1, 0x03, 0xF3,
     157        /* 84*/ 0xFF,
     158       
     159        /* 85*/ 0xE2, 0x0C, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD3, 0x07, 0xFF,
     160        /* 96*/ 0xE2, 0x06, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0x07, 0xFF,
     161        /*109*/ 0xFF,
     162       
     163        /*110*/ 0xE2, 0x0C, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD3, 0x27, 0xFF,
     164        /*121*/ 0xE2, 0x06, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0x27, 0xFF,
     165        /*134*/ 0xFF,
     166       
     167        /*135*/ 0xE2, 0x0C, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD3, 0x47, 0xFF,
     168        /*146*/ 0xE2, 0x06, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0x47, 0xFF,
     169        /*159*/ 0xFF,
     170       
     171        /*160*/ 0xE2, 0x0C, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD3, 0x57, 0xFF,
     172        /*171*/ 0xE2, 0x06, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0x57, 0xFF,
     173        /*184*/ 0xFF,
     174       
     175        /*185*/ 0xE2, 0x0C, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD3, 0x77, 0xFF,
     176        /*196*/ 0xE2, 0x06, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0x77, 0xFF,
     177        /*209*/ 0xFF,
     178       
     179        /*210*/ 0xE2, 0x0C, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD3, 0x97, 0xFF,
     180        /*221*/ 0xE2, 0x06, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0x97, 0xFF,
     181        /*234*/ 0xFF,
     182       
     183        /*235*/ 0xE2, 0x0C, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD3, 0xB7, 0xFF,
     184        /*246*/ 0xE2, 0x06, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0xB7, 0xFF,
     185        /*259*/ 0xFF,
     186       
     187        /*260*/ 0xE2, 0x0C, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD4, 0x07, 0xFF,
     188        /*271*/ 0xE2, 0x06, 0xE1, 0x02, 0xE0, 0x0F, 0xE6, 0xED, 0xD5, 0xF0, 0x0C, 0x07, 0xFF,
     189        /*284*/ 0xFF,
     190       
     191        /*285*/ 0xE2, 0x0B, 0xE1, 0x04, 0xE6, 0xED, 0xE0, 0x0A, 0xD0, 0xDB, 0x14, 0x0E, 0xFF,
     192        /*298*/ 0xE2, 0x0B, 0xE1, 0x04, 0xE6, 0xED, 0xE0, 0x0A, 0xD0, 0xDB, 0x32, 0x1E, 0xFF,
     193        /*311*/ 0xE2, 0x0B, 0xE1, 0x0B, 0xE6, 0xED, 0xE0, 0x0A, 0xD0, 0xDB, 0x50, 0x1E, 0xFF,
     194        /*324*/ 0xE2, 0x0B, 0xE1, 0x0B, 0xE6, 0xED, 0xE0, 0x0A, 0xD0, 0x0E, 0xFF,
     195        /*335*/ 0xE2, 0x0B, 0xE1, 0x02, 0xE6, 0xED, 0xE0, 0x0A, 0xD0, 0xDB, 0x0A, 0x0E, 0xFF,
     196        /*348*/ 0xFF,
     197       
     198        /*349*/ 0xE2, 0x03, 0xE1, 0x01, 0xE6, 0xED, 0xE0, 0x06, 0xD6, 0x17, 0xFF,
     199        /*360*/ 0xFF,
     200        /*361*/ 0xFF,
     201        /*362*/ 0xE2, 0x04, 0xE1, 0x04, 0xE6, 0xED, 0xE0, 0x06, 0xD5, 0xA7, 0xFF,
     202        /*373*/ 0xE2, 0x03, 0xE1, 0x06, 0xE6, 0xED, 0xE0, 0x06, 0xD6, 0x37, 0xFF,
     203        /*384*/ 0xE2, 0x04, 0xE1, 0x06, 0xE6, 0xED, 0xE0, 0x06, 0xD3, 0x87, 0xFF,
     204       
     205        /*395*/ 0xE2, 0x0C, 0xE1, 0x00, 0xE0, 0x04, 0xE6, 0xED, 0xD4, 0x0B, 0xE8, 0x0B, 0xFF,
     206        /*408*/ 0xE2, 0x0C, 0xE1, 0x03, 0xE0, 0x04, 0xE6, 0xED, 0xD4, 0xF0, 0x0C, 0x00,
     207                0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00,
     208                0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00,
     209                0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00,
     210                0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xE8, 0x00, 0xE8, 0x10, 0xFF,
     211        /*467*/ 0xE2, 0x0C, 0xE1, 0x00, 0xE0, 0x04, 0xE6, 0xED, 0xD4, 0x1B, 0xE8, 0x1B, 0xFF,
     212        /*480*/ 0xFF,
     213       
     214        /*481*/ 0xFF
     215};
     216
     217
     218/*
     219 * PSG_HuC6280
     220 */
     221
     222class PSG_HuC6280 {
     223private:
     224        typedef struct {
     225                uint16 frequency;
     226                uint8 control;
     227                uint8 balance;
     228                uint8 waveform[32];
     229                uint8 index;
     230                int16 dda;
     231                uint32 counter;
     232        } channel_t;
     233
     234        double _clock;
     235        double _rate;
     236        uint8 _select;
     237    uint8 _balance;
     238    channel_t _channel[8];
     239    int16 _volumeTable[32];
     240    uint32 _noiseFreqTable[32];
     241    uint32 _waveFreqTable[4096];
     242
     243public:
     244        void init();
     245        void reset();
     246        void write(int offset, byte data);
     247        void update(int16* samples, int sampleCnt);
     248       
     249        PSG_HuC6280(double clock, double samplerate);
     250};
     251
     252PSG_HuC6280::PSG_HuC6280(double clock, double samplerate) {
     253        _clock = clock;
     254    _rate = samplerate;
     255
     256    // Initialize PSG_HuC6280 emulator
     257    init();
     258}
     259
     260void PSG_HuC6280::init() {
     261    int i;
     262    double step;
     263
     264    // Loudest volume level for table
     265    double level = 65535.0 / 6.0 / 32.0;
     266
     267    // Clear context
     268        reset();
     269
     270    // Make waveform frequency table
     271    for(i = 0; i < 4096; i++) {
     272        step = ((_clock / _rate) * 4096) / (i+1);
     273        _waveFreqTable[(1 + i) & 0xFFF] = (uint32)step;
     274    }
     275
     276    // Make noise frequency table
     277    for(i = 0; i < 32; i++) {
     278        step = ((_clock / _rate) * 32) / (i+1);
     279        _noiseFreqTable[i] = (uint32)step;
     280    }
     281
     282    // Make volume table
     283    // PSG_HuC6280 has 48dB volume range spread over 32 steps
     284    step = 48.0 / 32.0;
     285    for(i = 0; i < 31; i++) {
     286        _volumeTable[i] = (uint16)level;
     287        level /= pow(10.0, step / 20.0);
     288    }
     289    _volumeTable[31] = 0;
     290}
     291
     292void PSG_HuC6280::reset() {
     293        _select = 0;
     294    _balance = 0xFF;
     295    memset(_channel, 0, sizeof(_channel));
     296    memset(_volumeTable, 0, sizeof(_volumeTable));
     297    memset(_noiseFreqTable, 0, sizeof(_noiseFreqTable));
     298    memset(_waveFreqTable, 0, sizeof(_waveFreqTable));
     299}
     300
     301void PSG_HuC6280::write(int offset, byte data) {
     302    channel_t *chan = &_channel[_select];
     303
     304    switch(offset & 0x0F) {
     305    case 0x00: // Channel select
     306        _select = data & 0x07;
     307        break;
     308
     309    case 0x01: // Global balance
     310        _balance  = data;
     311        break;
     312
     313    case 0x02: // Channel frequency (LSB)
     314        chan->frequency = (chan->frequency & 0x0F00) | data;
     315        chan->frequency &= 0x0FFF;
     316        break;
     317
     318    case 0x03: // Channel frequency (MSB)
     319        chan->frequency = (chan->frequency & 0x00FF) | (data << 8);
     320        chan->frequency &= 0x0FFF;
     321        break;
     322
     323    case 0x04: // Channel control (key-on, DDA mode, volume)
     324        // 1-to-0 transition of DDA bit resets waveform index
     325        if((chan->control & 0x40) && ((data & 0x40) == 0)) {
     326            chan->index = 0;
     327        }
     328        chan->control = data;
     329        break;
     330
     331    case 0x05: // Channel balance
     332        chan->balance = data;
     333        break;
     334
     335    case 0x06: // Channel waveform data
     336        switch(chan->control & 0xC0) {
     337        case 0x00:
     338            chan->waveform[chan->index & 0x1F] = data & 0x1F;
     339            chan->index = (chan->index + 1) & 0x1F;
     340            break;
     341
     342        case 0x40:
     343            break;
     344
     345        case 0x80:
     346            chan->waveform[chan->index & 0x1F] = data & 0x1F;
     347            chan->index = (chan->index + 1) & 0x1F;
     348            break;
     349
     350        case 0xC0:
     351            chan->dda = data & 0x1F;
     352            break;
     353        }
     354
     355        break;
     356
     357    case 0x07: // Noise control (enable, frequency)
     358    case 0x08: // LFO frequency
     359    case 0x09: // LFO control (enable, mode)
     360        break;
     361
     362    default:
     363        break;
     364    }
     365}
     366
     367void PSG_HuC6280::update(int16* samples, int sampleCnt) {
     368    static const int scale_tab[] = {
     369        0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
     370        0x10, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F
     371    };
     372    int ch;
     373    int i;
     374
     375    int lmal = (_balance >> 4) & 0x0F;
     376    int rmal = (_balance >> 0) & 0x0F;
     377    int vll, vlr;
     378
     379    lmal = scale_tab[lmal];
     380    rmal = scale_tab[rmal];
     381
     382    // Clear buffer
     383        memset(samples, 0, 2 * sampleCnt * sizeof(int16));
     384
     385    for(ch = 0; ch < 6; ch++) {
     386        // Only look at enabled channels
     387        if(_channel[ch].control & 0x80) {
     388            int lal = (_channel[ch].balance >> 4) & 0x0F;
     389            int ral = (_channel[ch].balance >> 0) & 0x0F;
     390            int al  = _channel[ch].control & 0x1F;
     391
     392            lal = scale_tab[lal];
     393            ral = scale_tab[ral];
     394
     395            // Calculate volume just as the patent says
     396            vll = (0x1F - lal) + (0x1F - al) + (0x1F - lmal);
     397            if(vll > 0x1F) vll = 0x1F;
     398
     399            vlr = (0x1F - ral) + (0x1F - al) + (0x1F - rmal);
     400            if(vlr > 0x1F) vlr = 0x1F;
     401
     402            vll = _volumeTable[vll];
     403            vlr = _volumeTable[vlr];
     404
     405            // Check channel mode
     406            if(_channel[ch].control & 0x40) {
     407                /* DDA mode */
     408                for(i = 0; i < sampleCnt; i++) {
     409                    samples[2*i]     += (int16)(vll * (_channel[ch].dda - 16));
     410                    samples[2*i + 1] += (int16)(vlr * (_channel[ch].dda - 16));
     411                }
     412            } else {
     413                /* Waveform mode */
     414                uint32 step = _waveFreqTable[_channel[ch].frequency];
     415                for(i = 0; i < sampleCnt; i += 1) {
     416                    int offset;
     417                    int16 data;
     418                    offset = (_channel[ch].counter >> 12) & 0x1F;
     419                    _channel[ch].counter += step;
     420                    _channel[ch].counter &= 0x1FFFF;
     421                    data = _channel[ch].waveform[offset];
     422                    samples[2*i]     += (int16)(vll * (data - 16));
     423                    samples[2*i + 1] += (int16)(vlr * (data - 16));
     424                }
     425            }
     426        }
     427    }
     428}
     429
     430
     431/*
     432 * Player_PCE
     433 */
     434
     435void Player_PCE::PSG_Write(int reg, byte data) {
     436        _psg->write(reg, data);
     437}
     438
     439void Player_PCE::setupWaveform(byte bank) {
     440        const byte *ptr = wave_table[bank];
     441        PSG_Write(4, 0x40);
     442        PSG_Write(4, 0x00);
     443        for (int i = 0; i < 32; ++i) {
     444                PSG_Write(6, ptr[i]);
     445        }
     446}
     447
     448// A541
     449void Player_PCE::procA541(channel_t *channel) {
     450        channel->soundDataPtr = NULL;
     451        channel->controlVecShort10 = 0;
     452
     453        channel->controlVecShort03 = 0;
     454        channel->controlVecShort06 = 0;
     455        channel->controlVec8 = 0;
     456        channel->controlVec9 = 0;
     457        channel->controlVec10 = 0;
     458        channel->soundUpdateCounter = 0;
     459        channel->controlVec18 = 0;
     460        channel->controlVec19 = 0;
     461        channel->controlVec23 = false;
     462        channel->controlVec24 = false;
     463        channel->controlVec21 = 0;
     464
     465    channel->waveformCtrl = 0x80;
     466}
     467
     468// A592
     469void Player_PCE::startSound(int sound) {
     470        channel_t *channel;
     471        const uint16 *ptr = sounds[sound_table[sound]];
     472
     473        for (int i = 0; i < 6; ++i) {
     474                channel = &channels[i];
     475                procA541(channel);
     476
     477                channel->controlVec24 = true;
     478                channel->waveformCtrl = 0;
     479                channel->controlVec0 = 0;
     480                channel->controlVec19 = 0;
     481                channel->controlVec18 = 0;
     482                channel->soundDataPtr = &data_table[*ptr++];
     483        }
     484}
     485
     486// A64B
     487void Player_PCE::updateSound() {
     488        for (int i = 0; i < 12; i++) {
     489                channel_t *channel = &channels[i];
     490                bool cond = true;
     491                if (i < 6) {
     492                        channel->controlVec21 ^= 0xFF;
     493                        if (!channel->controlVec21)
     494                                cond = false;
     495                }
     496                if (cond) {
     497                        processSoundData(channel);
     498                        procAB7F(channel);
     499                        procAC24(channel);
     500                        channel->controlVec11 = (channel->controlVecShort10 >> 11) | 0x80;
     501                        channel->balance = channel->balance2;
     502                }
     503        }
     504
     505        for (int i = 0; i < 6; ++i) {
     506                procA731(&channels[i]);
     507        }
     508}
     509
     510int Player_PCE::readBuffer(int16 *buffer, const int numSamples) {
     511        int sampleCopyCnt;
     512        int samplesLeft = numSamples;
     513
     514        _mutex.lock();
     515
     516        while (true) {
     517                // copy samples to output buffer
     518                sampleCopyCnt = (samplesLeft < _sampleBufferCnt) ? samplesLeft : _sampleBufferCnt;
     519                if (sampleCopyCnt > 0) {
     520                        memcpy(buffer, _sampleBuffer, sampleCopyCnt * sizeof(int16));
     521                        buffer += sampleCopyCnt;
     522                        samplesLeft -= sampleCopyCnt;
     523                        _sampleBufferCnt -= sampleCopyCnt;
     524                }
     525
     526                if (samplesLeft == 0)
     527                        break;
     528
     529                // retrieve samples for one timer period
     530                updateSound();
     531                _psg->update(_sampleBuffer, _samplesPerPeriod / 2);
     532                _sampleBufferCnt = _samplesPerPeriod;
     533        }
     534
     535        // copy remaining samples to the front of the buffer
     536        if (_sampleBufferCnt > 0) {
     537                memmove(&_sampleBuffer[0],
     538                        &_sampleBuffer[_samplesPerPeriod - _sampleBufferCnt],
     539                        _sampleBufferCnt * sizeof(int16));
     540        }
     541
     542        _mutex.unlock();
     543
     544        return numSamples;
     545}
     546
     547void Player_PCE::procA731(channel_t *channel) {
     548        PSG_Write(0, channel->id);
     549        PSG_Write(2, channel->freq & 0xFF);
     550        PSG_Write(3, (channel->freq >> 8) & 0xFF);
     551       
     552        int tmp = channel->controlVec11;
     553        if ((channel->controlVec11 & 0xC0) == 0x80) {
     554                tmp = channel->controlVec11 & 0x1F;
     555                if (tmp != 0) {
     556                        tmp -= channel->controlVec0;
     557                        if (tmp >= 0) {
     558                                tmp |= 0x80;
     559                        } else {
     560                                tmp = 0;
     561                        }
     562                }
     563        }
     564
     565        PSG_Write(5, channel->balance);
     566        if ((channel->waveformCtrl & 0x80) == 0) {
     567                channel->waveformCtrl |= 0x80;
     568                PSG_Write(0, channel->id);
     569                setupWaveform(channel->waveformCtrl & 0x7F);
     570        }
     571
     572        PSG_Write(4, tmp);
     573}
     574
     575// A793
     576void Player_PCE::processSoundData(channel_t *channel) {
     577        channel->soundUpdateCounter--;
     578        if (channel->soundUpdateCounter > 0) {
     579                return;
     580        }
     581
     582        while (true) {
     583                const byte *ptr = channel->soundDataPtr;       
     584                byte value = (ptr ? *ptr++ : 0xFF);
     585                if (value < 0xD0) {
     586                        int mult = (value & 0x0F) + 1;
     587                        channel->soundUpdateCounter = mult * channel->controlVec1;
     588                        value >>= 4;
     589                        procAA62(channel, value);
     590                        channel->soundDataPtr = ptr;
     591                        return;
     592                }
     593               
     594                // jump_table (A7F7)
     595                switch (value - 0xD0) {
     596                case 0: /*A85A*/
     597                case 1: /*A85D*/
     598                case 2: /*A861*/
     599                case 3: /*A865*/
     600                case 4: /*A869*/
     601                case 5: /*A86D*/
     602                case 6: /*A871*/
     603                        channel->controlVec2 = (value - 0xD0) * 12;
     604                        break;
     605                case 11: /*A8A8*/
     606                        channel->controlVecShort06 = (int8)*ptr++;
     607                        break;
     608                case 16: /*A8C2*/
     609                        channel->controlVec1 = *ptr++;
     610                        break;
     611                case 17: /*A8CA*/
     612                        channel->waveformCtrl = *ptr++;
     613                        break;
     614                case 18: /*A8D2*/
     615                        channel->controlVec10 = *ptr++;
     616                        break;
     617                case 22: /*A8F2*/
     618                        value = *ptr;
     619                        channel->balance = value;
     620                        channel->balance2 = value;
     621                        ptr++;
     622                        break;
     623                case 24: /*A905*/
     624                        channel->controlVec23 = true;
     625                        break;
     626                case 32: /*A921*/
     627                        *ptr++;
     628                        break;
     629                case 47:
     630                        channel->controlVec24 = false;
     631                        channel->controlVec10 &= 0x7F;
     632                        channel->controlVecShort10 &= 0x00FF;
     633                        return;
     634                default:
     635                        // unused -> ignore
     636                        break;
     637                }
     638
     639                channel->soundDataPtr = ptr;
     640        }
     641}
     642
     643void Player_PCE::procAA62(channel_t *channel, int a) {
     644        procACEA(channel, a);
     645        if (channel->controlVec23) {
     646                channel->controlVec23 = false;
     647                return;
     648        }
     649
     650        channel->controlVec18 = 0;
     651
     652        channel->controlVec10 |= 0x80;
     653        int y = channel->controlVec10 & 0x7F;
     654        channel->controlBufferPos = &control_data[control_offsets[y]];
     655        channel->controlVec5 = 0;
     656}
     657
     658void Player_PCE::procAB7F(channel_t *channel) {
     659        uint16 freqValue = channel->controlVecShort02;
     660        channel->controlVecShort02 += channel->controlVecShort03;
     661       
     662        int pos = freq_offset[channel->controlVec19] + channel->controlVec18;
     663        freqValue += freq_table[pos];
     664        if (freq_table[pos + 1] != 0x0800) {
     665                channel->controlVec18++;
     666        }
     667        freqValue += channel->controlVecShort06;
     668
     669        channel->freq = freqValue;
     670}
     671
     672void Player_PCE::procAC24(channel_t *channel) {
     673        if ((channel->controlVec10 & 0x80) == 0)
     674                return;
     675
     676        if (channel->controlVec5 == 0) {
     677                const byte *ctrlPtr = channel->controlBufferPos;
     678                byte value = *ctrlPtr++;
     679                while (value >= 0xF0) {
     680                        if (value == 0xF0) {
     681                                channel->controlVecShort10 = READ_LE_UINT16(ctrlPtr);
     682                                ctrlPtr += 2;
     683                        } else if (value == 0xFF) {
     684                                channel->controlVec10 &= 0x7F;
     685                                return;
     686                        } else {
     687                                // unused
     688                        }
     689                        value = *ctrlPtr++;
     690                }
     691                channel->controlVec5 = value;
     692                channel->controlVecShort09 = READ_LE_UINT16(ctrlPtr);
     693                ctrlPtr += 2;
     694                channel->controlBufferPos = ctrlPtr;
     695        }
     696
     697        channel->controlVecShort10 += channel->controlVecShort09;
     698        channel->controlVec5--;
     699}
     700
     701void Player_PCE::procACEA(channel_t *channel, int a) {
     702        int x = a +
     703                channel->controlVec2 +
     704                channel->controlVec8 +
     705                channel->controlVec9;
     706        channel->controlVecShort02 = lookup_table[x];
     707}
     708
     709Player_PCE::Player_PCE(ScummEngine *scumm, Audio::Mixer *mixer) {
     710        for (int i = 0; i < 12; ++i) {
     711                memset(&channels[i], 0, sizeof(channel_t));
     712                channels[i].id = i;
     713        }
     714
     715        _mixer = mixer;
     716        _sample_rate = _mixer->getOutputRate();
     717        _vm = scumm;
     718
     719        _samplesPerPeriod = 2 * (int)(_sample_rate / UPDATE_FREQ);
     720        _sampleBuffer = new int16[_samplesPerPeriod];
     721        _sampleBufferCnt = 0;
     722
     723        _psg = new PSG_HuC6280(PSG_CLOCK, _sample_rate);
     724
     725        _mixer->playInputStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true);
     726}
     727
     728Player_PCE::~Player_PCE() {
     729        _mixer->stopHandle(_soundHandle);       
     730        delete[] _sampleBuffer;
     731        delete _psg;
     732}
     733
     734void Player_PCE::stopSound(int nr) {
     735        // TODO: implement
     736}
     737
     738void Player_PCE::stopAllSounds() {
     739        // TODO: implement
     740}
     741
     742int Player_PCE::getSoundStatus(int nr) const {
     743        // TODO: status for each sound
     744        for (int i = 0; i < 6; ++i) {
     745                if (channels[i].controlVec24)
     746                        return 1;
     747        }
     748        return 0;
     749}
     750
     751int Player_PCE::getMusicTimer() const {
     752        return 0;
     753}
     754
     755} // End of namespace Scumm
  • engines/scumm/player_pce.h

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/engines/scumm/player_nes.h $
     22 * $Id: player_nes.h 27024 2007-05-30 21:56:52Z fingolfin $
     23 *
     24 */
     25
     26#ifndef SCUMM_PLAYER_PCE_H
     27#define SCUMM_PLAYER_PCE_H
     28
     29#include "common/scummsys.h"
     30#include "scumm/music.h"
     31#include "sound/audiostream.h"
     32#include "sound/mixer.h"
     33
     34namespace Scumm {
     35
     36class ScummEngine;
     37class PSG_HuC6280;
     38
     39class Player_PCE : public Audio::AudioStream, public MusicEngine {
     40private:
     41        struct channel_t {
     42                int id;
     43
     44                byte controlVec0;
     45                byte controlVec1;
     46                byte controlVec2;
     47                byte controlVec5;
     48                byte balance;
     49                byte balance2;
     50                byte controlVec8;
     51                byte controlVec9;
     52                byte controlVec10;
     53                byte controlVec11;
     54                int16 soundUpdateCounter;
     55                byte controlVec18;
     56                byte controlVec19;
     57                byte waveformCtrl;
     58                byte controlVec21;
     59                bool controlVec23;
     60                bool controlVec24;
     61
     62                uint16 controlVecShort02;
     63                uint16 controlVecShort03;
     64                int16 controlVecShort06;
     65                uint16 freq;
     66                uint16 controlVecShort09;
     67                uint16 controlVecShort10;
     68
     69                const byte* soundDataPtr;
     70                const byte* controlBufferPos;
     71        };
     72
     73public:
     74        Player_PCE(ScummEngine *scumm, Audio::Mixer *mixer);
     75        virtual ~Player_PCE();
     76
     77        virtual void setMusicVolume(int vol) { _maxvol = vol; };
     78        void startMusic(int songResIndex);
     79        virtual void startSound(int sound);
     80        virtual void stopSound(int sound);
     81        virtual void stopAllSounds();
     82        virtual int  getSoundStatus(int sound) const;
     83        virtual int  getMusicTimer() const;
     84
     85        // AudioStream API
     86        int readBuffer(int16 *buffer, const int numSamples);
     87        bool isStereo() const { return true; }
     88        bool endOfData() const { return false; }
     89        int getRate() const { return _sample_rate; }
     90
     91private:       
     92        ScummEngine *_vm;
     93        Audio::Mixer *_mixer;
     94        Audio::SoundHandle _soundHandle;
     95        int _sample_rate;
     96        int _maxvol;
     97
     98private:
     99        PSG_HuC6280 *_psg;
     100        channel_t channels[12];
     101        Common::Mutex _mutex;
     102
     103        // number of samples per timer period
     104        int _samplesPerPeriod;
     105        int16* _sampleBuffer;
     106        int _sampleBufferCnt;
     107
     108        void init();
     109        bool isPlaying();
     110
     111        void PSG_Write(int reg, byte data);
     112
     113        void setupWaveform(byte bank);
     114        void procA541(channel_t *channel);
     115        void updateSound();
     116        void procA731(channel_t *channel);
     117        void processSoundData(channel_t *channel);
     118        void procA9F3(int x);   
     119        void procAA62(channel_t *channel, int a);
     120        uint16 procAAF6(int x);
     121        void procAB7F(channel_t *channel);
     122        void procAC24(channel_t *channel);
     123        void procACEA(channel_t *channel, int a);
     124        void procAD21(int a, int x);
     125        void procAD29(int value);
     126        void procAD3D(int a, int x);
     127};
     128
     129} // End of namespace Scumm
     130
     131#endif
  • engines/scumm/scumm.cpp

     
    5252#include "scumm/he/sound_he.h"
    5353#include "scumm/object.h"
    5454#include "scumm/player_nes.h"
     55#include "scumm/player_pce.h"
    5556#include "scumm/player_v1.h"
    5657#include "scumm/player_v2.h"
    5758#include "scumm/player_v2a.h"
     
    17261727        } else if (_game.platform == Common::kPlatformAmiga && _game.version == 3) {
    17271728                _musicEngine = new Player_V3A(this, _mixer);
    17281729        } else if (_game.platform == Common::kPlatformPCEngine && _game.version == 3) {
    1729                 // TODO: Add support for music format
     1730                _musicEngine = new Player_PCE(this, _mixer);
    17301731        } else if (_game.platform == Common::kPlatformAmiga && _game.version <= 4) {
    17311732                _musicEngine = new Player_V4A(this, _mixer);
    17321733        } else if (_game.id == GID_MANIAC && _game.version == 1) {
  • engines/scumm/sound.cpp

     
    171171                        _currentCDSound = soundID;
    172172                        playCDTrack(tracks[soundID - 13], 1, 0, 0);
    173173                } else {
    174                         // FIXME: Sound effect resources are currently missing
    175                         printf("Sound %d unsupported\n", soundID);
     174                        if (_vm->_musicEngine) {
     175                                _vm->_musicEngine->startSound(soundID);
     176                        }
    176177                }
    177178                return;
    178179        }