/* Namco custom waveform sound generator 3 (Pacman hardware) Copyright (c) 2003,2004 Alessandro Scotti http://www.ascotti.org/ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "namcowsg3.h" NamcoWsg3::NamcoWsg3( unsigned masterClock ) { master_clock_ = masterClock; setSamplingRate( 0 ); for( int i=0; i<3; i++ ) { wave_offset_[i] = 0; } } void NamcoWsg3::setSoundPROM( const unsigned char * prom ) { memcpy( sound_prom_, prom, sizeof(sound_prom_) ); for( int i=0; i<32*8; i++ ) { sound_wave_data_[i] = (int)*prom++ - 8; } } void NamcoWsg3::getVoice( NamcoWsg3Voice * voice, int index ) const { int base = 5*index; voice->waveform = sound_regs_[ 0x05 + base ] & 0x07; voice->volume = sound_regs_[ 0x15 + base ] & 0x0F; unsigned f; f = (sound_regs_[ 0x14+base ] & 0x0F); f = (f << 4) | (sound_regs_[ 0x13+base ] & 0x0F); f = (f << 4) | (sound_regs_[ 0x12+base ] & 0x0F); f = (f << 4) | (sound_regs_[ 0x11+base ] & 0x0F); f = (f << 4); if( index == 0 ) { // The first voice has an extra 4-bit of data f |= (sound_regs_[ 0x10+base ] & 0x0F); } voice->frequency = f; } /* Play and mix the sound voices into the specified buffer. */ void NamcoWsg3::playSound( int * buf, int len ) { NamcoWsg3Voice voice; for( int index=0; index<3; index++ ) { getVoice( &voice, index ); if( voice.isActive() ) { unsigned offset = wave_offset_[index]; unsigned offset_step = voice.frequency * resample_step_; int * wave_data = sound_wave_data_ + 32 * voice.waveform; for( int i=0; i> 25) & 0x1F] * (int) voice.volume; offset += offset_step; } wave_offset_[index] = offset; } } } static unsigned addUint32( unsigned char * buffer, unsigned u ) { *buffer++ = (unsigned char) (u >> 24); *buffer++ = (unsigned char) (u >> 16); *buffer++ = (unsigned char) (u >> 8); *buffer = (unsigned char) (u); return 4; } static unsigned getUint32( unsigned char ** buffer ) { unsigned char * buf = *buffer; unsigned result = *buf++; result = (result << 8) | *buf++; result = (result << 8) | *buf++; result = (result << 8) | *buf++; *buffer = buf; return result; } unsigned NamcoWsg3::getSizeOfSnapshotBuffer() const { unsigned result = 4 + // master_clock_ 4 + // sampling_rate_ 4*3 + // wave_offset_ sizeof(sound_regs_) + sizeof(sound_prom_); return result; } unsigned NamcoWsg3::takeSnapshot( unsigned char * buffer ) { unsigned char * buf = buffer; buf += addUint32( buf, master_clock_ ); buf += addUint32( buf, sampling_rate_ ); buf += addUint32( buf, wave_offset_[0] ); buf += addUint32( buf, wave_offset_[1] ); buf += addUint32( buf, wave_offset_[2] ); memcpy( buf, sound_regs_, sizeof(sound_regs_) ); buf += sizeof(sound_regs_); memcpy( buf, sound_prom_, sizeof(sound_prom_) ); buf += sizeof(sound_prom_); return buf - buffer; } unsigned NamcoWsg3::restoreSnapshot( unsigned char * buffer ) { unsigned char * buf = buffer; unsigned char prom[ sizeof(sound_prom_) ]; master_clock_ = getUint32( &buf ); sampling_rate_ = getUint32( &buf ); wave_offset_[0] = getUint32( &buf ); wave_offset_[1] = getUint32( &buf ); wave_offset_[2] = getUint32( &buf ); memcpy( sound_regs_, buf, sizeof(sound_regs_) ); buf += sizeof(sound_regs_); memcpy( prom, buf, sizeof(prom) ); buf += sizeof(prom); setSoundPROM( prom ); return buf - buffer; }