Enable game sounds in PacBox. Sound is OFF by default but can be enabled from the menu. Enable a function for SWCODEC in the middle of the plugin API, so plugins must be made incompatible (full update).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27202 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
10b8e327d8
commit
cf73340f1e
10 changed files with 473 additions and 24 deletions
|
@ -637,9 +637,7 @@ static const struct plugin_api rockbox_api = {
|
|||
get_codec_filename,
|
||||
find_array_ptr,
|
||||
remove_array_ptr,
|
||||
#if defined(HAVE_RECORDING) && (defined(HAVE_LINE_IN) || defined(HAVE_MIC_IN))
|
||||
round_value_to_list32,
|
||||
#endif
|
||||
#endif /* CONFIG_CODEC == SWCODEC */
|
||||
get_metadata,
|
||||
mp3info,
|
||||
|
|
|
@ -144,12 +144,12 @@ void* plugin_get_buffer(size_t *buffer_size);
|
|||
#define PLUGIN_MAGIC 0x526F634B /* RocK */
|
||||
|
||||
/* increase this every time the api struct changes */
|
||||
#define PLUGIN_API_VERSION 187
|
||||
#define PLUGIN_API_VERSION 188
|
||||
|
||||
/* update this to latest version if a change to the api struct breaks
|
||||
backwards compatibility (and please take the opportunity to sort in any
|
||||
new function which are "waiting" at the end of the function table) */
|
||||
#define PLUGIN_MIN_API_VERSION 187
|
||||
#define PLUGIN_MIN_API_VERSION 188
|
||||
|
||||
/* plugin return codes */
|
||||
enum plugin_status {
|
||||
|
@ -782,12 +782,10 @@ struct plugin_api {
|
|||
const char *(*get_codec_filename)(int cod_spec);
|
||||
void ** (*find_array_ptr)(void **arr, void *ptr);
|
||||
int (*remove_array_ptr)(void **arr, void *ptr);
|
||||
#if defined(HAVE_RECORDING) && (defined(HAVE_LINE_IN) || defined(HAVE_MIC_IN))
|
||||
int (*round_value_to_list32)(unsigned long value,
|
||||
const unsigned long list[],
|
||||
int count,
|
||||
bool signd);
|
||||
#endif
|
||||
int (*round_value_to_list32)(unsigned long value,
|
||||
const unsigned long list[],
|
||||
int count,
|
||||
bool signd);
|
||||
#endif /* CONFIG_CODEC == SWCODEC */
|
||||
bool (*get_metadata)(struct mp3entry* id3, int fd, const char* trackname);
|
||||
bool (*mp3info)(struct mp3entry *entry, const char *filename);
|
||||
|
|
|
@ -2,6 +2,7 @@ arcade.c
|
|||
pacbox.c
|
||||
hardware.c
|
||||
z80.c
|
||||
wsg3.c
|
||||
#if defined(CPU_PP502x) && (LCD_WIDTH >= 288) && (LCD_HEIGHT >= 224)
|
||||
pacbox_arm.S
|
||||
#else
|
||||
|
|
|
@ -24,8 +24,10 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "pacbox.h"
|
||||
#include "arcade.h"
|
||||
#include "hardware.h"
|
||||
#include "wsg3.h"
|
||||
#include <string.h>
|
||||
#include "plugin.h"
|
||||
|
||||
|
@ -92,6 +94,43 @@ enum {
|
|||
FlipXY = 0x03
|
||||
};
|
||||
|
||||
// Namco 3-channel Wave Sound Generator wave data (8 waveforms with 32 4-bit entries each)
|
||||
static unsigned char default_sound_prom[] =
|
||||
{
|
||||
0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0D, 0x0E,
|
||||
0x0E, 0x0E, 0x0D, 0x0D, 0x0C, 0x0B, 0x0A, 0x09,
|
||||
0x07, 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x00,
|
||||
0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05,
|
||||
0x07, 0x0C, 0x0E, 0x0E, 0x0D, 0x0B, 0x09, 0x0A,
|
||||
0x0B, 0x0B, 0x0A, 0x09, 0x06, 0x04, 0x03, 0x05,
|
||||
0x07, 0x09, 0x0B, 0x0A, 0x08, 0x05, 0x04, 0x03,
|
||||
0x03, 0x04, 0x05, 0x03, 0x01, 0x00, 0x00, 0x02,
|
||||
0x07, 0x0A, 0x0C, 0x0D, 0x0E, 0x0D, 0x0C, 0x0A,
|
||||
0x07, 0x04, 0x02, 0x01, 0x00, 0x01, 0x02, 0x04,
|
||||
0x07, 0x0B, 0x0D, 0x0E, 0x0D, 0x0B, 0x07, 0x03,
|
||||
0x01, 0x00, 0x01, 0x03, 0x07, 0x0E, 0x07, 0x00,
|
||||
0x07, 0x0D, 0x0B, 0x08, 0x0B, 0x0D, 0x09, 0x06,
|
||||
0x0B, 0x0E, 0x0C, 0x07, 0x09, 0x0A, 0x06, 0x02,
|
||||
0x07, 0x0C, 0x08, 0x04, 0x05, 0x07, 0x02, 0x00,
|
||||
0x03, 0x08, 0x05, 0x01, 0x03, 0x06, 0x03, 0x01,
|
||||
0x00, 0x08, 0x0F, 0x07, 0x01, 0x08, 0x0E, 0x07,
|
||||
0x02, 0x08, 0x0D, 0x07, 0x03, 0x08, 0x0C, 0x07,
|
||||
0x04, 0x08, 0x0B, 0x07, 0x05, 0x08, 0x0A, 0x07,
|
||||
0x06, 0x08, 0x09, 0x07, 0x07, 0x08, 0x08, 0x07,
|
||||
0x07, 0x08, 0x06, 0x09, 0x05, 0x0A, 0x04, 0x0B,
|
||||
0x03, 0x0C, 0x02, 0x0D, 0x01, 0x0E, 0x00, 0x0F,
|
||||
0x00, 0x0F, 0x01, 0x0E, 0x02, 0x0D, 0x03, 0x0C,
|
||||
0x04, 0x0B, 0x05, 0x0A, 0x06, 0x09, 0x07, 0x08,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
};
|
||||
|
||||
/* Putting this in IRAM actually slows down the iPods, but is good for
|
||||
the Coldfire
|
||||
*/
|
||||
|
@ -110,6 +149,12 @@ void init_PacmanMachine(int dip)
|
|||
z80_reset();
|
||||
rb->memset( &ram_[0x4000], 0xFF, 0x1000 );
|
||||
|
||||
/* Initialize the WSG3 */
|
||||
wsg3_init(SoundClock);
|
||||
|
||||
/* Set the sound PROM to the default values for the original Namco chip */
|
||||
wsg3_set_sound_prom(default_sound_prom);
|
||||
|
||||
/* Initialize parameters */
|
||||
port1_ = 0xFF;
|
||||
port2_ = 0xFF;
|
||||
|
@ -595,6 +640,19 @@ void renderSprites( unsigned char * buffer )
|
|||
}
|
||||
}
|
||||
|
||||
void playSound( int * buf, int len )
|
||||
{
|
||||
/* Clear the buffer */
|
||||
memset( buf, 0, sizeof (int)*len);
|
||||
|
||||
/* Exit now if sound is disabled */
|
||||
if( (output_devices_ & SoundEnabled) == 0 )
|
||||
return;
|
||||
|
||||
/* Let the chip play the sound */
|
||||
wsg3_play_sound( buf, len );
|
||||
}
|
||||
|
||||
/* Enables/disables the speed hack. */
|
||||
int setSpeedHack( int enabled )
|
||||
{
|
||||
|
|
|
@ -123,6 +123,8 @@ void init_PacmanMachine(int dip);
|
|||
int run(void);
|
||||
void reset_PacmanMachine(void);
|
||||
void decodeROMs(void);
|
||||
void playSound( int * buf, int len );
|
||||
|
||||
|
||||
/**
|
||||
Tells the emulator that the status of an input device has changed.
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "plugin.h"
|
||||
#include "hardware.h"
|
||||
#include "wsg3.h"
|
||||
|
||||
/* The main data for Pacman */
|
||||
|
||||
|
@ -140,7 +141,7 @@ void writeByte( unsigned addr, unsigned char b )
|
|||
default:
|
||||
if( addr >= 0x5040 && addr < 0x5060 ) {
|
||||
// Sound registers
|
||||
//SOUND sound_chip_.setRegister( addr-0x5040, b );
|
||||
wsg3_set_register( addr-0x5040, b );
|
||||
}
|
||||
else if( addr >= 0x5060 && addr < 0x5070 ) {
|
||||
// Sprite coordinates, x/y pairs for 8 sprites
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "arcade.h"
|
||||
#include "pacbox.h"
|
||||
#include "pacbox_lcd.h"
|
||||
#include "wsg3.h"
|
||||
#include "lib/configfile.h"
|
||||
#include "lib/playback_control.h"
|
||||
|
||||
|
@ -40,10 +41,12 @@ struct pacman_settings {
|
|||
int bonus;
|
||||
int ghostnames;
|
||||
int showfps;
|
||||
int sound;
|
||||
};
|
||||
|
||||
static struct pacman_settings settings;
|
||||
static struct pacman_settings old_settings;
|
||||
static bool sound_playing = false;
|
||||
|
||||
#define SETTINGS_VERSION 1
|
||||
#define SETTINGS_MIN_VERSION 1
|
||||
|
@ -53,7 +56,7 @@ static char* difficulty_options[] = { "Normal", "Hard" };
|
|||
static char* numlives_options[] = { "1", "2", "3", "5" };
|
||||
static char* bonus_options[] = {"10000", "15000", "20000", "No Bonus"};
|
||||
static char* ghostnames_options[] = {"Normal", "Alternate"};
|
||||
static char* showfps_options[] = {"No", "Yes"};
|
||||
static char* yesno_options[] = {"No", "Yes"};
|
||||
|
||||
static struct configdata config[] =
|
||||
{
|
||||
|
@ -65,7 +68,9 @@ static struct configdata config[] =
|
|||
{TYPE_ENUM, 0, 2, { .int_p = &settings.ghostnames }, "Ghost Names",
|
||||
ghostnames_options},
|
||||
{TYPE_ENUM, 0, 2, { .int_p = &settings.showfps }, "Show FPS",
|
||||
showfps_options},
|
||||
yesno_options},
|
||||
{TYPE_ENUM, 0, 2, { .int_p = &settings.sound }, "Sound",
|
||||
yesno_options},
|
||||
};
|
||||
|
||||
static bool loadFile( const char * name, unsigned char * buf, int len )
|
||||
|
@ -173,9 +178,21 @@ static bool pacbox_menu(void)
|
|||
{ "Alternate", -1 },
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PBMI_DIFFICULTY = 0,
|
||||
PBMI_PACMEN_PER_GAME,
|
||||
PBMI_BONUS_LIFE,
|
||||
PBMI_GHOST_NAMES,
|
||||
PBMI_DISPLAY_FPS,
|
||||
PBMI_SOUND,
|
||||
PBMI_RESTART,
|
||||
PBMI_QUIT,
|
||||
};
|
||||
|
||||
MENUITEM_STRINGLIST(menu, "Pacbox Menu", NULL,
|
||||
"Difficulty", "Pacmen Per Game", "Bonus Life",
|
||||
"Ghost Names", "Display FPS",
|
||||
"Ghost Names", "Display FPS", "Sound",
|
||||
"Restart", "Quit");
|
||||
|
||||
rb->button_clear_queue();
|
||||
|
@ -189,7 +206,7 @@ static bool pacbox_menu(void)
|
|||
|
||||
switch(result)
|
||||
{
|
||||
case 0:
|
||||
case PBMI_DIFFICULTY:
|
||||
new_setting=settings.difficulty;
|
||||
rb->set_option("Difficulty", &new_setting, INT,
|
||||
difficulty_options , 2, NULL);
|
||||
|
@ -198,7 +215,7 @@ static bool pacbox_menu(void)
|
|||
need_restart=true;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case PBMI_PACMEN_PER_GAME:
|
||||
new_setting=settings.numlives;
|
||||
rb->set_option("Pacmen Per Game", &new_setting, INT,
|
||||
numlives_options , 4, NULL);
|
||||
|
@ -207,7 +224,7 @@ static bool pacbox_menu(void)
|
|||
need_restart=true;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case PBMI_BONUS_LIFE:
|
||||
new_setting=settings.bonus;
|
||||
rb->set_option("Bonus Life", &new_setting, INT,
|
||||
bonus_options , 4, NULL);
|
||||
|
@ -216,7 +233,7 @@ static bool pacbox_menu(void)
|
|||
need_restart=true;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case PBMI_GHOST_NAMES:
|
||||
new_setting=settings.ghostnames;
|
||||
rb->set_option("Ghost Names", &new_setting, INT,
|
||||
ghostname_options , 2, NULL);
|
||||
|
@ -225,11 +242,15 @@ static bool pacbox_menu(void)
|
|||
need_restart=true;
|
||||
}
|
||||
break;
|
||||
case 4: /* Show FPS */
|
||||
case PBMI_DISPLAY_FPS:
|
||||
rb->set_option("Display FPS",&settings.showfps,INT,
|
||||
noyes, 2, NULL);
|
||||
break;
|
||||
case 5: /* Restart */
|
||||
case PBMI_SOUND:
|
||||
rb->set_option("Sound",&settings.sound, INT,
|
||||
noyes, 2, NULL);
|
||||
break;
|
||||
case PBMI_RESTART:
|
||||
need_restart=true;
|
||||
menu_quit=1;
|
||||
break;
|
||||
|
@ -252,16 +273,93 @@ static bool pacbox_menu(void)
|
|||
restart game
|
||||
usb connected
|
||||
*/
|
||||
return (result==6);
|
||||
return (result==PBMI_QUIT);
|
||||
}
|
||||
|
||||
/* Sound is emulated in ISR context, so not much is done per sound frame */
|
||||
#define NBSAMPLES 128
|
||||
static uint32_t sound_buf[NBSAMPLES];
|
||||
static int raw_buf[NBSAMPLES] IBSS_ATTR;
|
||||
|
||||
/*
|
||||
Audio callback
|
||||
*/
|
||||
static void get_more(unsigned char **start, size_t *size)
|
||||
{
|
||||
int i;
|
||||
int32_t *out;
|
||||
int *raw;
|
||||
|
||||
/* Emulate the audio for the current register settings */
|
||||
playSound(raw_buf, NBSAMPLES);
|
||||
|
||||
out = sound_buf;
|
||||
raw = raw_buf;
|
||||
|
||||
/* Normalize the audio and convert to stereo */
|
||||
for (i = 0; i < NBSAMPLES; i++)
|
||||
{
|
||||
uint32_t sample = (uint16_t)*raw++ << 6;
|
||||
*out++ = sample | (sample << 16);
|
||||
}
|
||||
|
||||
*start = (unsigned char *)sound_buf;
|
||||
*size = NBSAMPLES*sizeof(sound_buf[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
Start the sound emulation
|
||||
*/
|
||||
static void start_sound(void)
|
||||
{
|
||||
int sr_index;
|
||||
|
||||
if (sound_playing)
|
||||
return;
|
||||
|
||||
#ifndef PLUGIN_USE_IRAM
|
||||
/* Ensure control of PCM - stopping music isn't obligatory */
|
||||
rb->plugin_get_audio_buffer(NULL);
|
||||
#endif
|
||||
|
||||
/* Get the closest rate >= to what is preferred */
|
||||
sr_index = rb->round_value_to_list32(PREFERRED_SAMPLING_RATE,
|
||||
rb->hw_freq_sampr, HW_NUM_FREQ, false);
|
||||
|
||||
if (rb->hw_freq_sampr[sr_index] < PREFERRED_SAMPLING_RATE
|
||||
&& sr_index > 0)
|
||||
{
|
||||
/* Round up */
|
||||
sr_index--;
|
||||
}
|
||||
|
||||
wsg3_set_sampling_rate(rb->hw_freq_sampr[sr_index]);
|
||||
|
||||
rb->pcm_set_frequency(rb->hw_freq_sampr[sr_index]);
|
||||
rb->pcm_play_data(get_more, NULL, 0);
|
||||
|
||||
sound_playing = true;
|
||||
}
|
||||
|
||||
/*
|
||||
Stop the sound emulation
|
||||
*/
|
||||
static void stop_sound(void)
|
||||
{
|
||||
if (!sound_playing)
|
||||
return;
|
||||
|
||||
rb->pcm_play_stop();
|
||||
rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
|
||||
|
||||
sound_playing = false;
|
||||
}
|
||||
|
||||
/*
|
||||
Runs the game engine for one frame.
|
||||
*/
|
||||
static int gameProc( void )
|
||||
{
|
||||
int x;
|
||||
int fps;
|
||||
char str[80];
|
||||
int status;
|
||||
|
@ -269,6 +367,9 @@ static int gameProc( void )
|
|||
int frame_counter = 0;
|
||||
int yield_counter = 0;
|
||||
|
||||
if (settings.sound)
|
||||
start_sound();
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Run the machine for one frame (1/60th second) */
|
||||
|
@ -289,14 +390,25 @@ static int gameProc( void )
|
|||
|| status == PACMAN_RC_MENU
|
||||
#endif
|
||||
) {
|
||||
bool menu_res;
|
||||
|
||||
end_time = *rb->current_tick;
|
||||
x = pacbox_menu();
|
||||
|
||||
stop_sound();
|
||||
|
||||
menu_res = pacbox_menu();
|
||||
|
||||
rb->lcd_clear_display();
|
||||
#ifdef HAVE_REMOTE_LCD
|
||||
rb->lcd_remote_clear_display();
|
||||
rb->lcd_remote_update();
|
||||
#endif
|
||||
if (x == 1) { return 1; }
|
||||
if (menu_res)
|
||||
return 1;
|
||||
|
||||
if (settings.sound)
|
||||
start_sound();
|
||||
|
||||
start_time += *rb->current_tick-end_time;
|
||||
}
|
||||
|
||||
|
@ -368,6 +480,9 @@ static int gameProc( void )
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
stop_sound();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -392,6 +507,7 @@ enum plugin_status plugin_start(const void* parameter)
|
|||
settings.bonus = 0; /* 10000 points */
|
||||
settings.ghostnames = 0; /* Normal names */
|
||||
settings.showfps = 0; /* Do not show FPS */
|
||||
settings.sound = 0; /* Sound off by default */
|
||||
|
||||
if (configfile_load(SETTINGS_FILENAME, config,
|
||||
sizeof(config)/sizeof(*config),
|
||||
|
|
|
@ -299,4 +299,7 @@
|
|||
#define FPS 20
|
||||
#endif
|
||||
|
||||
/* 16kHz sounds pretty good - use it if available */
|
||||
#define PREFERRED_SAMPLING_RATE SAMPR_16
|
||||
|
||||
#endif
|
||||
|
|
148
apps/plugins/pacbox/wsg3.c
Normal file
148
apps/plugins/pacbox/wsg3.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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(int * 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;
|
||||
int * 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] += 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;
|
||||
int * 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] += 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;
|
||||
int * 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] += 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;
|
||||
|
||||
for (i = 0; i < 32*8; i++)
|
||||
wsg3.sound_wave_data[i] = (int)*prom++ - 8;
|
||||
}
|
||||
|
||||
void wsg3_init(unsigned master_clock)
|
||||
{
|
||||
memset(&wsg3, 0, sizeof (struct wsg3));
|
||||
wsg3.master_clock = master_clock;
|
||||
}
|
124
apps/plugins/pacbox/wsg3.h
Normal file
124
apps/plugins/pacbox/wsg3.h
Normal file
|
@ -0,0 +1,124 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef WSG3_H
|
||||
#define WSG3_H
|
||||
|
||||
/**
|
||||
Namco 3-channel sound generator voice properties.
|
||||
|
||||
This information is only needed by applications that want to do their own
|
||||
sound rendering, as the playSound() function already plays and mixes all
|
||||
three voices.
|
||||
|
||||
@see PacmanMachine::playSound
|
||||
*/
|
||||
struct wsg3_voice
|
||||
{
|
||||
/** Volume (from 0 to 15) */
|
||||
unsigned volume;
|
||||
/** Index into the 4-bit 32-entry waveform table (0 to 7) */
|
||||
unsigned waveform;
|
||||
/** Frequency */
|
||||
unsigned frequency;
|
||||
};
|
||||
|
||||
|
||||
struct wsg3
|
||||
{
|
||||
unsigned master_clock;
|
||||
unsigned sampling_rate;
|
||||
unsigned char sound_regs[0x20];
|
||||
unsigned char sound_prom[32*8];
|
||||
unsigned resample_step;
|
||||
unsigned wave_offset[3];
|
||||
int sound_wave_data[32*8];
|
||||
};
|
||||
|
||||
extern struct wsg3 wsg3;
|
||||
|
||||
/**
|
||||
Constructor.
|
||||
|
||||
@param masterClock clock frequency of sound chip (in Hertz)
|
||||
|
||||
@see #wsg3_play_sound
|
||||
*/
|
||||
void wsg3_init(unsigned master_clock);
|
||||
|
||||
/**
|
||||
Sets the 256 byte PROM that contains the waveform table used by the sound chip.
|
||||
*/
|
||||
void wsg3_set_sound_prom( const unsigned char * prom );
|
||||
|
||||
/**
|
||||
Sets the value of the specified register.
|
||||
*/
|
||||
static inline void wsg3_set_register(unsigned reg, unsigned char value)
|
||||
{ wsg3.sound_regs[reg] = value; }
|
||||
|
||||
/**
|
||||
Returns the value of the specified register.
|
||||
*/
|
||||
static inline unsigned char wsg3_get_register(unsigned reg)
|
||||
{ return wsg3.sound_regs[reg]; }
|
||||
|
||||
/**
|
||||
Reproduces the sound that is currently being generated by the sound
|
||||
chip into the specified buffer.
|
||||
|
||||
The sound chip has three independent voices that generate 8-bit signed
|
||||
PCM audio. This function resamples the voices at the currently specified
|
||||
sampling rate and mixes them into the output buffer. The output buffer
|
||||
can be converted to 8-bit (signed) PCM by dividing each sample by 3 (since
|
||||
there are three voices) or it can be expanded to 16-bit by multiplying
|
||||
each sample by 85 (i.e. 256 divided by 3). If necessary, it is possible
|
||||
to approximate these values with 4 and 64 in order to use arithmetic
|
||||
shifts that are usually faster to execute.
|
||||
|
||||
Note: this function does not clear the content of the output buffer before
|
||||
mixing voices into it.
|
||||
|
||||
@param buf pointer to sound buffer that receives the audio samples
|
||||
@param len length of the sound buffer
|
||||
*/
|
||||
void wsg3_play_sound(int * buf, int len);
|
||||
|
||||
/**
|
||||
Returns the sampling rate currently in use for rendering sound.
|
||||
*/
|
||||
static inline unsigned wsg3_get_sampling_rate(void)
|
||||
{ return wsg3.sampling_rate; }
|
||||
|
||||
/**
|
||||
Sets the output sampling rate for playSound().
|
||||
|
||||
@param samplingRate sampling rate in Hertz (samples per second)
|
||||
*/
|
||||
void wsg3_set_sampling_rate(unsigned sampling_rate);
|
||||
|
||||
#endif /* WSG3_H */
|
Loading…
Reference in a new issue