2010-07-01 00:26:01 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* __________ __ ___.
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Pacbox - a Pacman Emulator for Rockbox
|
|
|
|
*
|
|
|
|
* Based on PIE - Pacman Instructional Emulator
|
|
|
|
*
|
|
|
|
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
#include "plugin.h"
|
|
|
|
#include "wsg3.h"
|
|
|
|
|
|
|
|
struct wsg3 wsg3;
|
|
|
|
|
|
|
|
static bool wsg3_get_voice(struct wsg3_voice *voice, int index)
|
|
|
|
{
|
|
|
|
int base = 5*index;
|
|
|
|
const unsigned char *regs = wsg3.sound_regs;
|
|
|
|
unsigned x;
|
|
|
|
|
|
|
|
x = regs[0x15 + base] & 0x0F;
|
|
|
|
|
|
|
|
if (x == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
voice->volume = x;
|
|
|
|
|
|
|
|
x = (regs[0x14 + base] & 0x0F);
|
|
|
|
x = (x << 4) | (regs[0x13 + base] & 0x0F);
|
|
|
|
x = (x << 4) | (regs[0x12 + base] & 0x0F);
|
|
|
|
x = (x << 4) | (regs[0x11 + base] & 0x0F);
|
|
|
|
x = (x << 4);
|
|
|
|
|
|
|
|
if (index == 0)
|
|
|
|
{
|
|
|
|
/* The first voice has an extra 4-bit of data */
|
|
|
|
x |= regs[0x10 + base] & 0x0F;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
voice->frequency = x;
|
|
|
|
|
|
|
|
voice->waveform = regs[0x05 + base] & 0x07;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-07-01 03:57:37 +00:00
|
|
|
void wsg3_play_sound(int16_t * buf, int len)
|
2010-07-01 00:26:01 +00:00
|
|
|
{
|
|
|
|
struct wsg3_voice voice;
|
|
|
|
|
|
|
|
if (wsg3_get_voice(&voice, 0))
|
|
|
|
{
|
|
|
|
unsigned offset = wsg3.wave_offset[0];
|
|
|
|
unsigned step = voice.frequency * wsg3.resample_step;
|
2010-07-01 03:57:37 +00:00
|
|
|
int16_t * wave_data = wsg3.sound_wave_data + 32 * voice.waveform;
|
2010-07-01 00:26:01 +00:00
|
|
|
int volume = voice.volume;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
{
|
|
|
|
/* Should be shifted right by 15, but we must also get rid
|
|
|
|
* of the 10 bits used for decimals */
|
2010-07-01 03:57:37 +00:00
|
|
|
buf[i] = (int)wave_data[(offset >> 25) & 0x1F] * volume;
|
2010-07-01 00:26:01 +00:00
|
|
|
offset += step;
|
|
|
|
}
|
|
|
|
|
|
|
|
wsg3.wave_offset[0] = offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wsg3_get_voice(&voice, 1))
|
|
|
|
{
|
|
|
|
unsigned offset = wsg3.wave_offset[1];
|
|
|
|
unsigned step = voice.frequency * wsg3.resample_step;
|
2010-07-01 03:57:37 +00:00
|
|
|
int16_t * wave_data = wsg3.sound_wave_data + 32 * voice.waveform;
|
2010-07-01 00:26:01 +00:00
|
|
|
int volume = voice.volume;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
{
|
|
|
|
/* Should be shifted right by 15, but we must also get rid
|
|
|
|
* of the 10 bits used for decimals */
|
2010-07-01 03:57:37 +00:00
|
|
|
buf[i] += (int)wave_data[(offset >> 25) & 0x1F] * volume;
|
2010-07-01 00:26:01 +00:00
|
|
|
offset += step;
|
|
|
|
}
|
|
|
|
|
|
|
|
wsg3.wave_offset[1] = offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wsg3_get_voice(&voice, 2))
|
|
|
|
{
|
|
|
|
unsigned offset = wsg3.wave_offset[2];
|
|
|
|
unsigned step = voice.frequency * wsg3.resample_step;
|
2010-07-01 03:57:37 +00:00
|
|
|
int16_t * wave_data = wsg3.sound_wave_data + 32 * voice.waveform;
|
2010-07-01 00:26:01 +00:00
|
|
|
int volume = voice.volume;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
{
|
|
|
|
/* Should be shifted right by 15, but we must also get rid
|
|
|
|
* of the 10 bits used for decimals */
|
2010-07-01 03:57:37 +00:00
|
|
|
buf[i] += (int)wave_data[(offset >> 25) & 0x1F] * volume;
|
2010-07-01 00:26:01 +00:00
|
|
|
offset += step;
|
|
|
|
}
|
|
|
|
|
|
|
|
wsg3.wave_offset[2] = offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void wsg3_set_sampling_rate(unsigned sampling_rate)
|
|
|
|
{
|
|
|
|
wsg3.sampling_rate = sampling_rate;
|
|
|
|
wsg3.resample_step = (wsg3.master_clock << 10) / sampling_rate;
|
|
|
|
}
|
|
|
|
|
|
|
|
void wsg3_set_sound_prom( const unsigned char * prom )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2010-07-01 03:57:37 +00:00
|
|
|
memcpy(wsg3.sound_prom, prom, 32*8);
|
|
|
|
|
|
|
|
/* Copy wave data and convert 4-bit unsigned -> 16-bit signed,
|
|
|
|
* prenormalized */
|
2010-07-01 00:26:01 +00:00
|
|
|
for (i = 0; i < 32*8; i++)
|
2010-07-01 03:57:37 +00:00
|
|
|
wsg3.sound_wave_data[i] = ((int16_t)wsg3.sound_prom[i] - 8) * 85;
|
2010-07-01 00:26:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void wsg3_init(unsigned master_clock)
|
|
|
|
{
|
|
|
|
memset(&wsg3, 0, sizeof (struct wsg3));
|
|
|
|
wsg3.master_clock = master_clock;
|
|
|
|
}
|