rockbox/apps/plugins/pacbox/wsg3.c
Michael Sevakis ceab0b04eb PacBox: Premultiply sound prom data on load rather than during emulation. Use 16-bit data for 'raw' output instead of int.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27208 a1c6a512-1295-4272-9138-f99709370657
2010-07-01 03:57:37 +00:00

152 lines
4.3 KiB
C

/***************************************************************************
* __________ __ ___.
* 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;
}
void wsg3_play_sound(int16_t * buf, int len)
{
struct wsg3_voice voice;
if (wsg3_get_voice(&voice, 0))
{
unsigned offset = wsg3.wave_offset[0];
unsigned step = voice.frequency * wsg3.resample_step;
int16_t * wave_data = wsg3.sound_wave_data + 32 * voice.waveform;
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 */
buf[i] = (int)wave_data[(offset >> 25) & 0x1F] * volume;
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;
int16_t * wave_data = wsg3.sound_wave_data + 32 * voice.waveform;
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 */
buf[i] += (int)wave_data[(offset >> 25) & 0x1F] * volume;
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;
int16_t * wave_data = wsg3.sound_wave_data + 32 * voice.waveform;
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 */
buf[i] += (int)wave_data[(offset >> 25) & 0x1F] * volume;
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;
memcpy(wsg3.sound_prom, prom, 32*8);
/* Copy wave data and convert 4-bit unsigned -> 16-bit signed,
* prenormalized */
for (i = 0; i < 32*8; i++)
wsg3.sound_wave_data[i] = ((int16_t)wsg3.sound_prom[i] - 8) * 85;
}
void wsg3_init(unsigned master_clock)
{
memset(&wsg3, 0, sizeof (struct wsg3));
wsg3.master_clock = master_clock;
}