summaryrefslogtreecommitdiff
path: root/contrib/nosefart/nes_apu.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/nosefart/nes_apu.c')
-rw-r--r--contrib/nosefart/nes_apu.c102
1 files changed, 73 insertions, 29 deletions
diff --git a/contrib/nosefart/nes_apu.c b/contrib/nosefart/nes_apu.c
index 4a2ed8f4d..474e2ca1a 100644
--- a/contrib/nosefart/nes_apu.c
+++ b/contrib/nosefart/nes_apu.c
@@ -57,6 +57,11 @@ static int8 noise_long_lut[APU_NOISE_32K];
static int8 noise_short_lut[APU_NOISE_93];
#endif /* !REALTIME_NOISE */
+/* $$$ ben : last error */
+#define SET_APU_ERROR(APU,X) \
+if (APU) (APU)->errstr = "apu: " X; else
+
+#define APU_MIX_ENABLE(BIT) (apu->mix_enable&(1<<(BIT)))
/* vblank length table used for rectangles, triangle, noise */
static const uint8 vbl_length[32] =
@@ -102,27 +107,32 @@ const int dmc_clocks[16] =
/* ratios of pos/neg pulse for rectangle waves */
static const int duty_lut[4] = { 2, 4, 8, 12 };
-#if 0 /* unused */
-static void apu_setcontext(apu_t *src_apu)
+
+void apu_setcontext(apu_t *src_apu)
{
apu = src_apu;
+ /* $$$ ben reset eoor string here. */
+ SET_APU_ERROR(apu,"no error");
}
-#endif
/*
** Simple queue routines
*/
#define APU_QEMPTY() (apu->q_head == apu->q_tail)
-static void apu_enqueue(apudata_t *d)
+static int apu_enqueue(apudata_t *d)
{
ASSERT(apu);
apu->queue[apu->q_head] = *d;
apu->q_head = (apu->q_head + 1) & APUQUEUE_MASK;
- if (APU_QEMPTY())
+ if (APU_QEMPTY()) {
log_printf("apu: queue overflow\n");
+ SET_APU_ERROR(apu,"queue overflow");
+ return -1;
+ }
+ return 0;
}
static apudata_t *apu_dequeue(void)
@@ -131,19 +141,32 @@ static apudata_t *apu_dequeue(void)
ASSERT(apu);
- if (APU_QEMPTY())
- log_printf("apu: queue empty\n");
-
+ if (APU_QEMPTY()) {
+ log_printf("apu: queue empty\n");
+ SET_APU_ERROR(apu,"queue empty");
+ /* $$$ ben : should return 0 ??? */
+ }
loc = apu->q_tail;
apu->q_tail = (apu->q_tail + 1) & APUQUEUE_MASK;
return &apu->queue[loc];
}
-void apu_setchan(int chan, boolean enabled)
+int apu_setchan(int chan, boolean enabled)
{
- ASSERT(apu);
- apu->mix_enable[chan] = enabled;
+ const unsigned int max = 6;
+ int old;
+
+ ASSERT(apu);
+ if ((unsigned int)chan >= max) {
+ SET_APU_ERROR(apu,"channel out of range");
+ return -1;
+ }
+ old = (apu->mix_enable>>chan) & 1;
+ if (enabled != (boolean)-1) {
+ apu->mix_enable = (apu->mix_enable & ~(1<<chan)) | ((!!enabled)<<chan);
+ }
+ return old;
}
/* emulation of the 15-bit shift register the
@@ -977,13 +1000,13 @@ void apu_process(void *buffer, int num_samples)
elapsed_cycles += APU_FROM_FIXED(apu->cycle_rate);
accum = 0;
- if (apu->mix_enable[0]) accum += apu_rectangle(&apu->rectangle[0]);
- if (apu->mix_enable[1]) accum += apu_rectangle(&apu->rectangle[1]);
- if (apu->mix_enable[2]) accum += apu_triangle(&apu->triangle);
- if (apu->mix_enable[3]) accum += apu_noise(&apu->noise);
- if (apu->mix_enable[4]) accum += apu_dmc(&apu->dmc);
+ if (APU_MIX_ENABLE(0)) accum += apu_rectangle(&apu->rectangle[0]);
+ if (APU_MIX_ENABLE(1)) accum += apu_rectangle(&apu->rectangle[1]);
+ if (APU_MIX_ENABLE(2)) accum += apu_triangle(&apu->triangle);
+ if (APU_MIX_ENABLE(3)) accum += apu_noise(&apu->noise);
+ if (APU_MIX_ENABLE(4)) accum += apu_dmc(&apu->dmc);
- if (apu->ext && apu->mix_enable[5]) accum += apu->ext->process();
+ if (apu->ext && APU_MIX_ENABLE(5)) accum += apu->ext->process();
/* do any filtering */
if (APU_FILTER_NONE != apu->filter_type)
@@ -1012,11 +1035,12 @@ void apu_process(void *buffer, int num_samples)
/* signed 16-bit output, unsigned 8-bit */
if (16 == apu->sample_bits) {
- *((int16 *) buffer) = (int16) accum;
- buffer = (int16 *) buffer + 1;
- } else {
- *((uint8 *) buffer) = (accum >> 8) ^ 0x80;
- buffer = (int8 *) buffer + 1;
+ *(int16 *)(buffer) = (int16) accum;
+ buffer += sizeof(int16);
+ }
+ else {
+ *(uint8 *)(buffer) = (accum >> 8) ^ 0x80;
+ buffer += sizeof(uint8);
}
}
@@ -1025,10 +1049,18 @@ void apu_process(void *buffer, int num_samples)
}
/* set the filter type */
-void apu_setfilter(int filter_type)
+/* $$$ ben :
+ * Add a get feature (filter_type == -1) and returns old filter type
+ */
+int apu_setfilter(int filter_type)
{
+ int old;
ASSERT(apu);
- apu->filter_type = filter_type;
+ old = apu->filter_type;
+ if (filter_type != -1) {
+ apu->filter_type = filter_type;
+ }
+ return old;
}
void apu_reset(void)
@@ -1057,7 +1089,7 @@ void apu_reset(void)
apu->ext->reset();
}
-static void apu_build_luts(int num_samples)
+void apu_build_luts(int num_samples)
{
int i;
@@ -1090,12 +1122,15 @@ static void apu_setactive(apu_t *active)
apu_t *apu_create(int sample_rate, int refresh_rate, int sample_bits, boolean stereo)
{
apu_t *temp_apu;
- int channel;
+/* int channel; */
temp_apu = malloc(sizeof(apu_t));
if (NULL == temp_apu)
return NULL;
+ /* $$$ ben : safety net, in case we forgot to init something */
+ memset(temp_apu,0,sizeof(apu_t));
+ SET_APU_ERROR(temp_apu,"no error");
temp_apu->sample_rate = sample_rate;
temp_apu->refresh_rate = refresh_rate;
temp_apu->sample_bits = sample_bits;
@@ -1114,8 +1149,9 @@ apu_t *apu_create(int sample_rate, int refresh_rate, int sample_bits, boolean st
apu_setactive(temp_apu);
apu_reset();
- for (channel = 0; channel < 6; channel++)
- apu_setchan(channel, TRUE);
+ temp_apu->mix_enable = 0x3F;
+/* for (channel = 0; channel < 6; channel++) */
+/* apu_setchan(channel, TRUE); */
apu_setfilter(APU_FILTER_LOWPASS);
@@ -1137,15 +1173,23 @@ void apu_destroy(apu_t *src_apu)
}
}
-void apu_setext(apu_t *src_apu, apuext_t *ext)
+int apu_setext(apu_t *src_apu, apuext_t *ext)
{
ASSERT(src_apu);
+ /* $$$ ben : seem cleaner like this */
+ if (src_apu->ext) {
+ src_apu->ext->shutdown();
+ }
+
src_apu->ext = ext;
/* initialize it */
if (src_apu->ext)
src_apu->ext->init();
+
+ /* $$$ ben : May be one day extension int () will return error code */
+ return 0;
}
/* this exists for external mixing routines */