mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-11-12 06:32:34 -05:00
added xrick game
original xrick code by 'BigOrno' at: http://www.bigorno.net/xrick/ Rockbox port, plus bugfixes at: https://github.com/pierluigi-vicinanza/xrick Further changes: * Additonal fixes from g#3026 * Port to modern plugin API * Add Pluginlib keymap fallback * Support all >1bpp screens * Fix build warnings in miniz * Better error message when resources are missing Change-Id: Id83928bc2539901b0221692f65cbca41389c58e7
This commit is contained in:
parent
6f1e67e5e3
commit
102c374248
88 changed files with 16514 additions and 62 deletions
483
apps/plugins/xrick/system/syssnd_rockbox.c
Normal file
483
apps/plugins/xrick/system/syssnd_rockbox.c
Normal file
|
|
@ -0,0 +1,483 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Port of xrick, a Rick Dangerous clone, to Rockbox.
|
||||
* See http://www.bigorno.net/xrick/
|
||||
*
|
||||
* Copyright (C) 2008-2014 Pierluigi Vicinanza
|
||||
*
|
||||
* 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 "xrick/config.h"
|
||||
|
||||
#ifdef ENABLE_SOUND
|
||||
|
||||
#include "xrick/system/system.h"
|
||||
|
||||
#include "xrick/game.h"
|
||||
#include "xrick/debug.h"
|
||||
#include "xrick/system/syssnd_rockbox.h"
|
||||
|
||||
#include "plugin.h"
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
const U8 syssnd_period = 20;
|
||||
|
||||
/*
|
||||
* Local variables
|
||||
*/
|
||||
enum
|
||||
{
|
||||
SYSSND_MIX_CHANNELS = 5,
|
||||
SYSSND_MIX_SAMPLES = 1024, /* try changing this value if sound mixing is too slow or choppy */
|
||||
SYSSND_SOURCE_SAMPLES = SYSSND_MIX_SAMPLES / 2
|
||||
};
|
||||
|
||||
/* channels to be mixed */
|
||||
static channel_t channels[SYSSND_MIX_CHANNELS];
|
||||
/* buffer used to mix sounds sent to pcm playback, stores 16b stereo 44Khz audio samples */
|
||||
enum { AUDIO_BUFFER_COUNT = 4 };
|
||||
typedef struct
|
||||
{
|
||||
U32 data[SYSSND_MIX_SAMPLES];
|
||||
size_t length; /* in 8 bit mono samples */
|
||||
} mix_buffer_t;
|
||||
static mix_buffer_t mixBuffers[AUDIO_BUFFER_COUNT];
|
||||
static size_t writeIndex;
|
||||
static size_t readIndex;
|
||||
static size_t fillCount;
|
||||
static bool isAudioPlaying;
|
||||
static bool isAudioInitialised = false;
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
static void endChannel(size_t c);
|
||||
static void get_more(const void **start, size_t *size);
|
||||
|
||||
/*
|
||||
* Deactivate channel
|
||||
*/
|
||||
static void endChannel(size_t c)
|
||||
{
|
||||
channels[c].loop = 0;
|
||||
channels[c].sound = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Audio callback
|
||||
*/
|
||||
static void get_more(const void **start, size_t *size)
|
||||
{
|
||||
if (fillCount > 0)
|
||||
{
|
||||
/* Store output data address and size. */
|
||||
*start = mixBuffers[readIndex].data;
|
||||
*size = mixBuffers[readIndex].length * 8;
|
||||
|
||||
/* Free this part of output buffer. */
|
||||
mixBuffers[readIndex].length = 0;
|
||||
|
||||
/* Advance to the next part of output buffer. */
|
||||
readIndex = (readIndex + 1) & (AUDIO_BUFFER_COUNT - 1);
|
||||
fillCount--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Nothing to play. */
|
||||
isAudioPlaying = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Mix audio samples and fill playback buffer
|
||||
*/
|
||||
void syssnd_update(void)
|
||||
{
|
||||
if (!isAudioInitialised)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
size_t c;
|
||||
size_t sampleOffset;
|
||||
size_t maxSampleCount;
|
||||
bool isFirstSound;
|
||||
U8 *sourceBuf, *sourceBufEnd;
|
||||
U32 *destBuf;
|
||||
|
||||
/* Cancel if whole buffer filled. */
|
||||
if (fillCount >= (AUDIO_BUFFER_COUNT - 1))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
maxSampleCount = 0;
|
||||
|
||||
sampleOffset = mixBuffers[writeIndex].length;
|
||||
destBuf = mixBuffers[writeIndex].data + sampleOffset * 2;
|
||||
|
||||
isFirstSound = true;
|
||||
for (c = 0; c < SYSSND_MIX_CHANNELS ; ++c)
|
||||
{
|
||||
U32 * mixBuffer;
|
||||
size_t sampleCount;
|
||||
channel_t * channel = &channels[c];
|
||||
|
||||
if (!channel->sound /* no sound to play on this channel */
|
||||
|| (channel->loop == 0)) /* channel is inactive */
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isFirstSound)
|
||||
{
|
||||
/* clear mixing buffer */
|
||||
rb->memset(destBuf, 0, (SYSSND_MIX_SAMPLES - (sampleOffset * 2)) * sizeof(U32));
|
||||
isFirstSound = false;
|
||||
}
|
||||
|
||||
sampleCount = MIN(SYSSND_SOURCE_SAMPLES - sampleOffset, channel->len);
|
||||
if (maxSampleCount < sampleCount)
|
||||
{
|
||||
maxSampleCount = sampleCount;
|
||||
}
|
||||
|
||||
/* mix sound samples */
|
||||
mixBuffer = destBuf;
|
||||
sourceBuf = channel->buf;
|
||||
sourceBufEnd = channel->buf + sampleCount;
|
||||
while (sourceBuf < sourceBufEnd)
|
||||
{
|
||||
/* Convert from unsigned 8 bit mono 22khz to signed 16 bit stereo 44khz */
|
||||
const int sourceSample = *sourceBuf++;
|
||||
int monoSample = (sourceSample - 0x80) << 8;
|
||||
U32 stereoSample = *mixBuffer;
|
||||
monoSample += (S32)(stereoSample) >> 16;
|
||||
if (monoSample >= 0x8000)
|
||||
{
|
||||
monoSample = 0x7FFF;
|
||||
}
|
||||
else if (monoSample < -0x8000)
|
||||
{
|
||||
monoSample = -0x8000;
|
||||
}
|
||||
stereoSample = (U16)monoSample | ((U16)monoSample << 16);
|
||||
*mixBuffer++ = stereoSample;
|
||||
*mixBuffer++ = stereoSample;
|
||||
}
|
||||
channel->buf = sourceBufEnd;
|
||||
|
||||
channel->len -= sampleCount;
|
||||
if (channel->len == 0) /* ending ? */
|
||||
{
|
||||
if (channel->loop > 0)
|
||||
{
|
||||
channel->loop--;
|
||||
}
|
||||
if (channel->loop)
|
||||
{
|
||||
/* just loop */
|
||||
IFDEBUG_AUDIO2(sys_printf("xrick/audio: channel %d - loop\n", c););
|
||||
channel->buf = channel->sound->buf;
|
||||
channel->len = channel->sound->len;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* end for real */
|
||||
IFDEBUG_AUDIO2(sys_printf("xrick/audio: channel %d - end\n", c););
|
||||
endChannel(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (maxSampleCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mixBuffers[writeIndex].length += maxSampleCount;
|
||||
|
||||
/* Advance one part of audio buffer. */
|
||||
writeIndex = (writeIndex + 1) & (AUDIO_BUFFER_COUNT - 1);
|
||||
fillCount++;
|
||||
|
||||
if (!isAudioPlaying && fillCount > 0)
|
||||
{
|
||||
rb->pcm_play_data(&get_more, NULL, NULL, 0);
|
||||
isAudioPlaying = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise audio
|
||||
*/
|
||||
bool syssnd_init(void)
|
||||
{
|
||||
if (isAudioInitialised)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
IFDEBUG_AUDIO(sys_printf("xrick/audio: start\n"););
|
||||
|
||||
rb->talk_disable(true);
|
||||
|
||||
/* Stop playback to reconfigure audio settings and acquire audio buffer */
|
||||
rb->mixer_channel_stop(PCM_MIXER_CHAN_PLAYBACK);
|
||||
|
||||
#if INPUT_SRC_CAPS != 0
|
||||
/* Select playback */
|
||||
rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
|
||||
rb->audio_set_output_source(AUDIO_SRC_PLAYBACK);
|
||||
#endif
|
||||
|
||||
rb->pcm_set_frequency(HW_FREQ_44);
|
||||
rb->pcm_apply_settings();
|
||||
|
||||
rb->memset(channels, 0, sizeof(channels));
|
||||
rb->memset(mixBuffers, 0, sizeof(mixBuffers));
|
||||
|
||||
writeIndex = 0;
|
||||
readIndex = 0;
|
||||
fillCount = 0;
|
||||
isAudioPlaying = false;
|
||||
|
||||
isAudioInitialised = true;
|
||||
IFDEBUG_AUDIO(sys_printf("xrick/audio: ready\n"););
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Shutdown
|
||||
*/
|
||||
void syssnd_shutdown(void)
|
||||
{
|
||||
if (!isAudioInitialised)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Stop playback. */
|
||||
rb->pcm_play_stop();
|
||||
|
||||
/* Reset playing status. */
|
||||
isAudioPlaying = false;
|
||||
|
||||
/* Restore default sampling rate. */
|
||||
rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
|
||||
rb->pcm_apply_settings();
|
||||
|
||||
rb->talk_disable(false);
|
||||
|
||||
isAudioInitialised = false;
|
||||
IFDEBUG_AUDIO(sys_printf("xrick/audio: stop\n"););
|
||||
}
|
||||
|
||||
/*
|
||||
* Play a sound
|
||||
*
|
||||
* loop: number of times the sound should be played, -1 to loop forever
|
||||
*
|
||||
* NOTE if sound is already playing, simply reset it (i.e. can not have
|
||||
* twice the same sound playing -- tends to become noisy when too many
|
||||
* bad guys die at the same time).
|
||||
*/
|
||||
void syssnd_play(sound_t *sound, S8 loop)
|
||||
{
|
||||
size_t c;
|
||||
|
||||
if (!isAudioInitialised || !sound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
c = 0;
|
||||
while (channels[c].sound != sound &&
|
||||
channels[c].loop != 0 &&
|
||||
c < SYSSND_MIX_CHANNELS)
|
||||
{
|
||||
c++;
|
||||
}
|
||||
if (c >= SYSSND_MIX_CHANNELS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sound->buf)
|
||||
{
|
||||
syssnd_load(sound);
|
||||
if (!sound->buf)
|
||||
{
|
||||
sys_error("(audio) can not load %s", sound->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
IFDEBUG_AUDIO(
|
||||
if (channels[c].sound == sound)
|
||||
{
|
||||
sys_printf("xrick/audio: already playing %s on channel %d - resetting\n",
|
||||
sound->name, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
sys_printf("xrick/audio: playing %s on channel %d\n", sound->name, c);
|
||||
}
|
||||
);
|
||||
|
||||
channels[c].loop = loop;
|
||||
channels[c].sound = sound;
|
||||
channels[c].buf = sound->buf;
|
||||
channels[c].len = sound->len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pause all sounds
|
||||
*/
|
||||
void syssnd_pauseAll(bool pause)
|
||||
{
|
||||
if (!isAudioInitialised)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rb->pcm_play_lock();
|
||||
rb->mixer_channel_play_pause(PCM_MIXER_CHAN_PLAYBACK, !pause);
|
||||
rb->pcm_play_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop a sound
|
||||
*/
|
||||
void syssnd_stop(sound_t *sound)
|
||||
{
|
||||
size_t c;
|
||||
|
||||
if (!isAudioInitialised || !sound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (c = 0; c < SYSSND_MIX_CHANNELS; c++)
|
||||
{
|
||||
if (channels[c].sound == sound)
|
||||
{
|
||||
endChannel(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Stops all channels.
|
||||
*/
|
||||
void syssnd_stopAll(void)
|
||||
{
|
||||
size_t c;
|
||||
|
||||
if (!isAudioInitialised)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (c = 0; c < SYSSND_MIX_CHANNELS; c++)
|
||||
{
|
||||
if (channels[c].sound)
|
||||
{
|
||||
endChannel(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Load a sound.
|
||||
*/
|
||||
void syssnd_load(sound_t *sound)
|
||||
{
|
||||
int bytesRead;
|
||||
file_t fp;
|
||||
bool success;
|
||||
|
||||
if (!isAudioInitialised || !sound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
success = false;
|
||||
do
|
||||
{
|
||||
sound->buf = sysmem_push(sound->len);
|
||||
if (!sound->buf)
|
||||
{
|
||||
sys_error("(audio) not enough memory for \"%s\", %d bytes needed", sound->name, sound->len);
|
||||
break;
|
||||
}
|
||||
|
||||
fp = sysfile_open(sound->name);
|
||||
if (!fp)
|
||||
{
|
||||
sys_error("(audio) unable to open \"%s\"", sound->name);
|
||||
break;
|
||||
}
|
||||
|
||||
sysfile_seek(fp, sizeof(wave_header_t), SEEK_SET); /* skip WAVE header */
|
||||
|
||||
bytesRead = sysfile_read(fp, sound->buf, sound->len, 1);
|
||||
sysfile_close(fp);
|
||||
if (bytesRead != 1)
|
||||
{
|
||||
sys_error("(audio) unable to read from \"%s\"", sound->name);
|
||||
break;
|
||||
}
|
||||
|
||||
success = true;
|
||||
} while (false);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
sysmem_pop(sound->buf);
|
||||
sound->buf = NULL;
|
||||
sound->len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
IFDEBUG_AUDIO(sys_printf("xrick/audio: successfully loaded \"%s\"\n", sound->name););
|
||||
}
|
||||
|
||||
/*
|
||||
* Unload a sound.
|
||||
*/
|
||||
void syssnd_unload(sound_t *sound)
|
||||
{
|
||||
if (!isAudioInitialised || !sound || !sound->buf)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sysmem_pop(sound->buf);
|
||||
sound->buf = NULL;
|
||||
sound->len = 0;
|
||||
}
|
||||
|
||||
#endif /* ENABLE_SOUND */
|
||||
|
||||
/* eof */
|
||||
Loading…
Add table
Add a link
Reference in a new issue