improved the sound implementation
(still has too much latency, although mainly due to other parts of the menu)
This commit is contained in:
parent
5e5da4d1a8
commit
b719c4389f
20
inc/hashtable.h
Normal file
20
inc/hashtable.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
typedef struct hashtable hashtable;
|
||||||
|
void hashtable_destroy(hashtable *t);
|
||||||
|
typedef struct hashtable_entry hashtable_entry;
|
||||||
|
hashtable_entry *hashtable_body_allocate(unsigned int capacity);
|
||||||
|
hashtable *hashtable_create();
|
||||||
|
void hashtable_remove(hashtable *t,char *key);
|
||||||
|
void hashtable_resize(hashtable *t,unsigned int capacity);
|
||||||
|
void hashtable_set(hashtable *t,char *key,void *value);
|
||||||
|
void *hashtable_get(hashtable *t,char *key);
|
||||||
|
unsigned int hashtable_find_slot(hashtable *t,char *key);
|
||||||
|
unsigned long hashtable_hash(char *str);
|
||||||
|
struct hashtable {
|
||||||
|
unsigned int size;
|
||||||
|
unsigned int capacity;
|
||||||
|
hashtable_entry* body;
|
||||||
|
};
|
||||||
|
struct hashtable_entry {
|
||||||
|
char* key;
|
||||||
|
void* value;
|
||||||
|
};
|
5
inc/sound.h
Normal file
5
inc/sound.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
void sndInit(void);
|
||||||
|
void sndPlayBGM(char* filename);
|
||||||
|
void sndStopAll(void);
|
||||||
|
void sndPlaySFX(char* filename);
|
||||||
|
void sndUpdate(void);
|
BIN
res/filesystem/bgm21.it
Normal file
BIN
res/filesystem/bgm21.it
Normal file
Binary file not shown.
159
src/hashtable.c
Normal file
159
src/hashtable.c
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
/**
|
||||||
|
* Hashtable implementation
|
||||||
|
* (c) 2011 @marekweb
|
||||||
|
*
|
||||||
|
* Uses dynamic addressing with linear probing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "hashtable.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interface section used for `makeheaders`.
|
||||||
|
*/
|
||||||
|
#if INTERFACE
|
||||||
|
struct hashtable_entry {
|
||||||
|
char* key;
|
||||||
|
void* value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hashtable {
|
||||||
|
unsigned int size;
|
||||||
|
unsigned int capacity;
|
||||||
|
hashtable_entry* body;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HASHTABLE_INITIAL_CAPACITY 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the hash value for the given string.
|
||||||
|
* Implements the djb k=33 hash function.
|
||||||
|
*/
|
||||||
|
unsigned long hashtable_hash(char* str)
|
||||||
|
{
|
||||||
|
unsigned long hash = 5381;
|
||||||
|
int c;
|
||||||
|
while ((c = *str++))
|
||||||
|
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find an available slot for the given key, using linear probing.
|
||||||
|
*/
|
||||||
|
unsigned int hashtable_find_slot(hashtable* t, char* key)
|
||||||
|
{
|
||||||
|
int index = hashtable_hash(key) % t->capacity;
|
||||||
|
while (t->body[index].key != NULL && strcmp(t->body[index].key, key) != 0) {
|
||||||
|
index = (index + 1) % t->capacity;
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the item associated with the given key, or NULL if not found.
|
||||||
|
*/
|
||||||
|
void* hashtable_get(hashtable* t, char* key)
|
||||||
|
{
|
||||||
|
int index = hashtable_find_slot(t, key);
|
||||||
|
if (t->body[index].key != NULL) {
|
||||||
|
return t->body[index].value;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign a value to the given key in the table.
|
||||||
|
*/
|
||||||
|
void hashtable_set(hashtable* t, char* key, void* value)
|
||||||
|
{
|
||||||
|
int index = hashtable_find_slot(t, key);
|
||||||
|
if (t->body[index].key != NULL) {
|
||||||
|
/* Entry exists; update it. */
|
||||||
|
t->body[index].value = value;
|
||||||
|
} else {
|
||||||
|
t->size++;
|
||||||
|
/* Create a new entry */
|
||||||
|
if ((float)t->size / t->capacity > 0.8) {
|
||||||
|
/* Resize the hash table */
|
||||||
|
hashtable_resize(t, t->capacity * 2);
|
||||||
|
index = hashtable_find_slot(t, key);
|
||||||
|
}
|
||||||
|
t->body[index].key = key;
|
||||||
|
t->body[index].value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a key from the table
|
||||||
|
*/
|
||||||
|
void hashtable_remove(hashtable* t, char* key)
|
||||||
|
{
|
||||||
|
int index = hashtable_find_slot(t, key);
|
||||||
|
if (t->body[index].key != NULL) {
|
||||||
|
t->body[index].key = NULL;
|
||||||
|
t->body[index].value = NULL;
|
||||||
|
t->size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new, empty hashtable
|
||||||
|
*/
|
||||||
|
hashtable* hashtable_create()
|
||||||
|
{
|
||||||
|
hashtable* new_ht = malloc(sizeof(hashtable));
|
||||||
|
new_ht->size = 0;
|
||||||
|
new_ht->capacity = HASHTABLE_INITIAL_CAPACITY;
|
||||||
|
new_ht->body = hashtable_body_allocate(new_ht->capacity);
|
||||||
|
return new_ht;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/**
|
||||||
|
* Adds all items from another table.
|
||||||
|
*/
|
||||||
|
hashtable* hashtable_merge(hashtable* ht, hashtable* other)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate a new memory block with the given capacity.
|
||||||
|
*/
|
||||||
|
hashtable_entry* hashtable_body_allocate(unsigned int capacity)
|
||||||
|
{
|
||||||
|
return (hashtable_entry*)calloc(capacity, sizeof(hashtable_entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize the allocated memory.
|
||||||
|
* Warning: clears the table of all entries.
|
||||||
|
*/
|
||||||
|
void hashtable_resize(hashtable* t, unsigned int capacity)
|
||||||
|
{
|
||||||
|
assert(capacity >= t->size);
|
||||||
|
unsigned int old_capacity = t->capacity;
|
||||||
|
hashtable_entry* old_body = t->body;
|
||||||
|
t->body = hashtable_body_allocate(capacity);
|
||||||
|
t->capacity = capacity;
|
||||||
|
for (int i = 0; i < old_capacity; i++) {
|
||||||
|
if (old_body[i].key != NULL) {
|
||||||
|
hashtable_set(t, old_body[i].key, old_body[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the table and deallocate it from memory. This does not deallocate the contained items.
|
||||||
|
*/
|
||||||
|
void hashtable_destroy(hashtable* t)
|
||||||
|
{
|
||||||
|
free(t->body);
|
||||||
|
free(t);
|
||||||
|
}
|
66
src/menu.c
66
src/menu.c
@ -36,7 +36,7 @@
|
|||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
|
|
||||||
//sound
|
//sound
|
||||||
#include <mikmod.h>
|
#include "sound.h"
|
||||||
#include "mp3.h"
|
#include "mp3.h"
|
||||||
|
|
||||||
//debug
|
//debug
|
||||||
@ -2567,48 +2567,18 @@ void playSound(int snd)
|
|||||||
{
|
{
|
||||||
//no thread support in libdragon yet, sounds pause the menu for a time :/
|
//no thread support in libdragon yet, sounds pause the menu for a time :/
|
||||||
|
|
||||||
//maybe global
|
|
||||||
int v1;
|
|
||||||
|
|
||||||
static SAMPLE *add_sfx = NULL;
|
|
||||||
if (snd == 1)
|
if (snd == 1)
|
||||||
add_sfx = Sample_Load("rom://ed64_mono.wav");
|
sndPlaySFX("rom://ed64_mono.wav");
|
||||||
|
|
||||||
if (snd == 2)
|
if (snd == 2)
|
||||||
add_sfx = Sample_Load("rom://bamboo.wav");
|
sndPlaySFX("rom://bamboo.wav");
|
||||||
|
|
||||||
if (snd == 3)
|
if (snd == 3)
|
||||||
add_sfx = Sample_Load("rom://warning.wav");
|
sndPlaySFX("rom://warning.wav");
|
||||||
|
|
||||||
if (snd == 4)
|
if (snd == 4)
|
||||||
add_sfx = Sample_Load("rom://done.wav");
|
sndPlaySFX("rom://done.wav");
|
||||||
|
|
||||||
MikMod_SetNumVoices(-1, 2);
|
|
||||||
|
|
||||||
if (!add_sfx)
|
|
||||||
{
|
|
||||||
MikMod_Exit();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MikMod_EnableOutput();
|
|
||||||
|
|
||||||
audio_write_silence();
|
|
||||||
audio_write_silence();
|
|
||||||
|
|
||||||
v1 = Sample_Play(add_sfx, 0, 0);
|
|
||||||
Voice_SetVolume(v1, 100);
|
|
||||||
|
|
||||||
//maybe put update function into a int/vblank callback
|
|
||||||
for (int s = 0; s < 50; s++)
|
|
||||||
{
|
|
||||||
MikMod_Update();
|
|
||||||
sleep(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
MikMod_DisableOutput();
|
|
||||||
Sample_Free(add_sfx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//draws the next char at the text input screen
|
//draws the next char at the text input screen
|
||||||
@ -3355,21 +3325,11 @@ int main(void)
|
|||||||
|
|
||||||
if (sound_on)
|
if (sound_on)
|
||||||
{
|
{
|
||||||
audio_init(44100, 2);
|
|
||||||
//load soundsystem
|
//load soundsystem
|
||||||
|
audio_init(44100, 2);
|
||||||
|
sndInit();
|
||||||
|
|
||||||
timer_init();
|
timer_init();
|
||||||
|
|
||||||
MikMod_RegisterAllDrivers();
|
|
||||||
MikMod_RegisterAllLoaders();
|
|
||||||
|
|
||||||
md_mode = 0;
|
|
||||||
md_mode |= DMODE_16BITS;
|
|
||||||
md_mode |= DMODE_SOFT_MUSIC;
|
|
||||||
md_mode |= DMODE_SOFT_SNDFX;
|
|
||||||
|
|
||||||
md_mixfreq = audio_get_frequency();
|
|
||||||
|
|
||||||
MikMod_Init("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fast_boot)
|
if (!fast_boot)
|
||||||
@ -3378,6 +3338,9 @@ int main(void)
|
|||||||
playSound(1);
|
playSound(1);
|
||||||
|
|
||||||
sleep(2000); //splash screen duration
|
sleep(2000); //splash screen duration
|
||||||
|
|
||||||
|
//todo: if bgm is enabled, we should start it...
|
||||||
|
//sndPlayBGM("rom://bgm21.it");
|
||||||
}
|
}
|
||||||
|
|
||||||
border_color_1 = translate_color(border_color_1_s);
|
border_color_1 = translate_color(border_color_1_s);
|
||||||
@ -3434,6 +3397,8 @@ int main(void)
|
|||||||
//system main-loop with controller inputs-scan
|
//system main-loop with controller inputs-scan
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
sndUpdate();
|
||||||
|
|
||||||
if (playing == 1)
|
if (playing == 1)
|
||||||
playing = update_mp3(buf_ptr, buf_size);
|
playing = update_mp3(buf_ptr, buf_size);
|
||||||
|
|
||||||
@ -4329,8 +4294,9 @@ int main(void)
|
|||||||
drawBoxNumber(disp, 2);
|
drawBoxNumber(disp, 2);
|
||||||
display_show(disp);
|
display_show(disp);
|
||||||
|
|
||||||
printText("ALT64: v0.1.8.6.1.1", 9, 8, disp);
|
printText("Altra64: v0.1.8.6.1.2", 9, 8, disp);
|
||||||
printText(" ", 9, -1, disp);
|
sprintf(firmware_str, "ED64 firmware: v%03x", evd_getFirmVersion());
|
||||||
|
printText(firmware_str , 9, -1, disp);
|
||||||
printText("by Saturnu", 9, -1, disp);
|
printText("by Saturnu", 9, -1, disp);
|
||||||
printText("& JonesAlmighty", 9, -1, disp);
|
printText("& JonesAlmighty", 9, -1, disp);
|
||||||
printText(" ", 9, -1, disp);
|
printText(" ", 9, -1, disp);
|
||||||
|
108
src/sound.c
Normal file
108
src/sound.c
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#include <mikmod.h>
|
||||||
|
#include <libdragon.h> //needed for audio_get_frequency()
|
||||||
|
#include "hashtable.h"
|
||||||
|
|
||||||
|
MODULE *moduleBGM = NULL;
|
||||||
|
|
||||||
|
/* sound effects */
|
||||||
|
hashtable* samples = NULL;
|
||||||
|
|
||||||
|
/* voices */
|
||||||
|
SBYTE voiceSFX;
|
||||||
|
|
||||||
|
void sndInit(void)
|
||||||
|
{
|
||||||
|
samples = hashtable_create();
|
||||||
|
|
||||||
|
/* register all the drivers */
|
||||||
|
MikMod_RegisterAllDrivers();
|
||||||
|
MikMod_RegisterAllLoaders();
|
||||||
|
|
||||||
|
/* initialize the library */
|
||||||
|
md_mode = 0;
|
||||||
|
md_mode |= DMODE_16BITS;
|
||||||
|
md_mode |= DMODE_SOFT_MUSIC;
|
||||||
|
md_mode |= DMODE_SOFT_SNDFX;
|
||||||
|
md_mode |= DMODE_INTERP;
|
||||||
|
|
||||||
|
md_mixfreq = audio_get_frequency();
|
||||||
|
|
||||||
|
MikMod_Init("");
|
||||||
|
|
||||||
|
/* reserve 2 voices for sound effects */
|
||||||
|
MikMod_SetNumVoices(-1, 2);
|
||||||
|
|
||||||
|
/* get ready to play */
|
||||||
|
MikMod_EnableOutput();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void sndPlayBGM(char* filename)
|
||||||
|
{
|
||||||
|
if (Player_Active())
|
||||||
|
{
|
||||||
|
Player_Stop();
|
||||||
|
}
|
||||||
|
Player_Free(moduleBGM);
|
||||||
|
moduleBGM = NULL;
|
||||||
|
|
||||||
|
moduleBGM = Player_Load(filename, 64, 0);
|
||||||
|
|
||||||
|
if (moduleBGM)
|
||||||
|
{
|
||||||
|
Player_Start(moduleBGM);
|
||||||
|
Player_SetVolume(20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sndStopAll(void)
|
||||||
|
{
|
||||||
|
Voice_Stop(voiceSFX);
|
||||||
|
Player_Stop();
|
||||||
|
MikMod_DisableOutput();
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
while (index < samples->capacity) {
|
||||||
|
Sample_Free(samples->body[index].value);
|
||||||
|
index = index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hashtable_destroy(samples);
|
||||||
|
|
||||||
|
Player_Free(moduleBGM);
|
||||||
|
moduleBGM = NULL;
|
||||||
|
|
||||||
|
samples = hashtable_create();
|
||||||
|
//MikMod_Exit(); //I dont think we should ever exit as that would mean reinitialising?!
|
||||||
|
}
|
||||||
|
|
||||||
|
void sndPlaySFX(char* filename)
|
||||||
|
{
|
||||||
|
if (!Voice_Stopped(voiceSFX))
|
||||||
|
{
|
||||||
|
Voice_Stop(voiceSFX);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (hashtable_get(samples, filename) == NULL)
|
||||||
|
{
|
||||||
|
hashtable_set(samples, filename, Sample_Load(filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
//audio_write_silence();
|
||||||
|
Voice_SetVolume(voiceSFX, 200);
|
||||||
|
voiceSFX = Sample_Play(hashtable_get(samples, filename), 0, 0);
|
||||||
|
|
||||||
|
MikMod_Update(); //force an update so that the voice is registered as playing!
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void sndUpdate(void)
|
||||||
|
{
|
||||||
|
if (!Voice_Stopped(voiceSFX) || Player_Active())
|
||||||
|
{
|
||||||
|
MikMod_Update();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user