Commit 34d25d9d authored by Erik Faye-Lund's avatar Erik Faye-Lund
Browse files

un-c++-ized quite some code.

git-svn-id: https://pimpmobile.svn.sourceforge.net/svnroot/pimpmobile/trunk@105 3d5ecaf0-f903-0410-b953-c2c1a4d75763
parent 08cf28e8
......@@ -13,7 +13,7 @@
#include <string.h>
#include "../include/pimpmobile.h"
#include "../src/mixer.h"
#include "../src/pimp_mixer.h"
#include "../src/config.h"
#include "gbfs.h"
......
#include <stdlib.h>
#include <assert.h>
#include "mixer.h"
#include "pimp_mixer.h"
#include "pimp_debug.h"
#include <gba_systemcalls.h>
#include <gba_dma.h>
#include <gba_timers.h>
using namespace mixer;
/*
mixing:
for each chan
......@@ -35,170 +30,158 @@ end for
*/
volatile channel_t mixer::channels[CHANNELS] IWRAM_DATA;
#include <gba_console.h>
#include <stdio.h>
s32 event_delta = 0;
s32 event_cursor = 0;
bool detect_loop_event(channel_t &chan, size_t samples)
BOOL detect_loop_event(pimp_mixer_channel_state *chan, int samples)
{
assert(samples != 0);
ASSERT(samples != 0);
s32 check_point;
s32 end_sample = chan.sample_cursor + chan.sample_cursor_delta * samples;
s32 end_sample = chan->sample_cursor + chan->sample_cursor_delta * samples;
switch (chan.loop_type)
switch (chan->loop_type)
{
case LOOP_TYPE_NONE:
check_point = chan.sample_length;
break;
case LOOP_TYPE_FORWARD:
check_point = chan.loop_end;
break;
case LOOP_TYPE_PINGPONG:
if (chan.sample_cursor_delta >= 0)
{
// moving forwards through the sample
check_point = chan.loop_end;
}
else
{
// moving backwards through the sample
check_point = chan.loop_start;
if (end_sample < (check_point << 12))
case LOOP_TYPE_NONE:
check_point = chan->sample_length;
break;
case LOOP_TYPE_FORWARD:
check_point = chan->loop_end;
break;
case LOOP_TYPE_PINGPONG:
if (chan->sample_cursor_delta >= 0)
{
event_delta = -chan.sample_cursor_delta;
event_cursor = -((check_point << 12) - chan.sample_cursor);
return true;
// moving forwards through the sample
check_point = chan->loop_end;
}
else return false;
}
break;
else
{
// moving backwards through the sample
check_point = chan->loop_start;
if (end_sample < (check_point << 12))
{
event_delta = -chan->sample_cursor_delta;
event_cursor = -((check_point << 12) - chan->sample_cursor);
return TRUE;
}
return FALSE;
}
break;
}
if (end_sample >= (check_point << 12))
{
event_delta = chan.sample_cursor_delta;
event_cursor = (check_point << 12) - chan.sample_cursor;
return true;
event_delta = chan->sample_cursor_delta;
event_cursor = (check_point << 12) - chan->sample_cursor;
return TRUE;
}
return false;
return FALSE;
}
// returns false if we hit sample-end
bool process_loop_event(channel_t &chan)
BOOL process_loop_event(pimp_mixer_channel_state *chan)
{
switch (chan.loop_type)
switch (chan->loop_type)
{
case LOOP_TYPE_NONE:
return false;
break;
case LOOP_TYPE_FORWARD:
do
{
chan.sample_cursor -= (chan.loop_end - chan.loop_start) << 12;
}
while (chan.sample_cursor >= (chan.loop_end << 12));
break;
case LOOP_TYPE_PINGPONG:
do
{
if (chan.sample_cursor_delta >= 0)
case LOOP_TYPE_NONE:
return FALSE;
break;
case LOOP_TYPE_FORWARD:
do
{
chan.sample_cursor -= chan.loop_end << 12;
chan.sample_cursor = -chan.sample_cursor;
chan.sample_cursor += chan.loop_end << 12;
chan->sample_cursor -= (chan->loop_end - chan->loop_start) << 12;
}
else
while (chan->sample_cursor >= (chan->loop_end << 12));
break;
case LOOP_TYPE_PINGPONG:
do
{
chan.sample_cursor -= chan.loop_start << 12;
chan.sample_cursor = -chan.sample_cursor;
chan.sample_cursor += chan.loop_start << 12;
if (chan->sample_cursor_delta >= 0)
{
chan->sample_cursor -= chan->loop_end << 12;
chan->sample_cursor = -chan->sample_cursor;
chan->sample_cursor += chan->loop_end << 12;
}
else
{
chan->sample_cursor -= chan->loop_start << 12;
chan->sample_cursor = -chan->sample_cursor;
chan->sample_cursor += chan->loop_start << 12;
}
chan->sample_cursor_delta = -chan->sample_cursor_delta;
}
chan.sample_cursor_delta = -chan.sample_cursor_delta;
}
while (chan.sample_cursor > (chan.loop_end << 12) || chan.sample_cursor < (chan.loop_start << 12));
break;
while ((chan->sample_cursor > (chan->loop_end << 12)) || (chan->sample_cursor < (chan->loop_start << 12)));
break;
}
return true;
}
inline void timing_start()
{
REG_TM3CNT_H = 0;
REG_TM3CNT_L = 0;
REG_TM3CNT_H = TIMER_START;
}
inline void timing_end()
{
unsigned int fjall = REG_TM3CNT_L;
// iprintf("cycles pr sample: %i\n", fjall / SOUND_BUFFER_SIZE);
// iprintf("%i per cent cpu\n", (fjall * 1000) / 280896);
return TRUE;
}
u32 dc_offs = 0;
static inline void mix_channel(channel_t &chan, s32 *target, size_t samples)
{
if (chan.volume < 1) return;
dc_offs += chan.volume * 128;
assert(samples > 0);
void pimp_mixer_mix_channel(pimp_mixer_channel_state *chan, s32 *target, u32 samples)
{
if (chan->volume < 1) return;
dc_offs += chan->volume * 128;
ASSERT(samples > 0);
while (samples > 0 && detect_loop_event(chan, samples) == true)
{
do
{
assert((chan.sample_cursor >> 12) < chan.sample_length);
assert(chan.sample_data != 0);
ASSERT((chan->sample_cursor >> 12) < chan->sample_length);
ASSERT(chan->sample_data != 0);
s32 samp = ((u8*)chan.sample_data)[chan.sample_cursor >> 12];
chan.sample_cursor += chan.sample_cursor_delta;
*target++ += samp * chan.volume;
s32 samp = ((u8*)chan->sample_data)[chan->sample_cursor >> 12];
chan->sample_cursor += chan->sample_cursor_delta;
*target++ += samp * chan->volume;
samples--;
event_cursor -= event_delta;
}
while (event_cursor > 0);
assert(samples >= 0);
ASSERT(samples >= 0);
if (process_loop_event(chan) == false)
{
// the sample has stopped, we need to fill the rest of the buffer with the dc-offset, so it doesn't ruin our unsigned mixing-thing
while (samples--)
{
*target++ += chan.volume * 128;
*target++ += chan->volume * 128;
}
// terminate sample
chan.sample_data = 0;
chan->sample_data = 0;
return;
}
}
assert(chan.sample_data != 0);
chan.sample_cursor = mix_samples(target, samples, chan.sample_data, chan.volume, chan.sample_cursor, chan.sample_cursor_delta);
ASSERT(chan->sample_data != 0);
chan->sample_cursor = pimp_mixer_mix_samples(target, samples, chan->sample_data, chan->volume, chan->sample_cursor, chan->sample_cursor_delta);
}
void mixer::reset()
void pimp_mixer_reset(pimp_mixer *mixer)
{
ASSERT(mixer != NULL);
for (u32 c = 0; c < CHANNELS; ++c)
{
channels[c].sample_data = 0;
channels[c].sample_cursor = 0;
channels[c].sample_cursor_delta = 0;
mixer->channels[c].sample_data = 0;
mixer->channels[c].sample_cursor = 0;
mixer->channels[c].sample_cursor_delta = 0;
}
}
s32 sound_mix_buffer[SOUND_BUFFER_SIZE] IWRAM_DATA;
void mixer::mix(s8 *target, size_t samples)
void pimp_mixer_mix(pimp_mixer *mixer, s8 *target, int samples)
{
assert(samples > 0);
ASSERT(samples > 0);
// zero out the sample-buffer
u32 zero = 0;
......@@ -207,10 +190,10 @@ void mixer::mix(s8 *target, size_t samples)
dc_offs = 0;
for (u32 c = 0; c < CHANNELS; ++c)
{
channel_t &chan = (channel_t &)channels[c];
if (0 != chan.sample_data) mix_channel(chan, sound_mix_buffer, samples);
pimp_mixer_channel_state *chan = &mixer->channels[c];
if (NULL != chan->sample_data) pimp_mixer_mix_channel(chan, sound_mix_buffer, samples);
}
dc_offs >>= 8;
clip_samples(target, sound_mix_buffer, samples, dc_offs);
pimp_mixer_clip_samples(target, sound_mix_buffer, samples, dc_offs);
}
#ifndef MIXER_H
#define MIXER_H
#include "pimp_types.h"
#include "config.h"
namespace mixer
{
typedef enum
{
LOOP_TYPE_NONE,
LOOP_TYPE_FORWARD,
LOOP_TYPE_PINGPONG
} loop_type_t;
typedef struct channel_state_
{
u32 sample_length;
u32 loop_start;
u32 loop_end;
loop_type_t loop_type;
const u8 *sample_data;
u32 sample_cursor;
s32 sample_cursor_delta;
s32 volume;
} channel_t;
extern volatile channel_t channels[CHANNELS];
void reset();
void mix(s8 *target, size_t samples);
u32 mix_samples(s32 *target, u32 samples, const u8 *sample_data, u32 vol, u32 sample_cursor, s32 sample_cursor_delta);
void clip_samples(s8 *target, s32 *source, u32 samples, u32 dc_offs);
}
#endif /* MIXER_H */
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "mixer.h"
#include "pimp_mixer.h"
#include "pimp_debug.h"
#include <gba_interrupt.h>
......@@ -198,7 +198,7 @@ static u32 mix_bresenham(s32 *target, u32 samples, const u8 *sample_data, u32 vo
return ((sample_data - old_sample_data - 1) << 12) + (sample_cursor >> 20);
}
u32 mixer::mix_samples(s32 *target, u32 samples, const u8 *sample_data, u32 vol, u32 sample_cursor, s32 sample_cursor_delta)
u32 pimp_mixer_mix_samples(s32 *target, u32 samples, const u8 *sample_data, u32 vol, u32 sample_cursor, s32 sample_cursor_delta)
{
assert(target != 0);
assert(sample_data != 0);
......@@ -227,7 +227,7 @@ u32 mixer::mix_samples(s32 *target, u32 samples, const u8 *sample_data, u32 vol,
}
}
void mixer::clip_samples(s8 *target, s32 *source, u32 samples, u32 dc_offs)
void pimp_mixer_clip_samples(s8 *target, s32 *source, u32 samples, u32 dc_offs)
{
assert(target != NULL);
assert(source != NULL);
......
......@@ -8,12 +8,14 @@
#include <stdio.h>
pimp_mod_context __pimp_ctx;
pimp_mixer __pimp_mixer;
static s8 sound_buffers[2][SOUND_BUFFER_SIZE] IWRAM_DATA;
static u32 sound_buffer_index = 0;
extern "C" void pimp_init(const void *module, const void *sample_bank)
{
init_pimp_mod_context(&__pimp_ctx, (const pimp_module*)module, (const u8*)sample_bank);
init_pimp_mod_context(&__pimp_ctx, (const pimp_module*)module, (const u8*)sample_bank, &__pimp_mixer);
u32 zero = 0;
CpuFastSet(&zero, &sound_buffers[0][0], DMA_SRC_FIXED | ((SOUND_BUFFER_SIZE / 4) * 2));
......@@ -59,7 +61,7 @@ extern "C" void pimp_frame()
if (true == locked) return; // whops, we're in the middle of filling. sorry.
locked = true;
pimp_render(__pimp_ctx, sound_buffers[sound_buffer_index], SOUND_BUFFER_SIZE);
pimp_render(&__pimp_ctx, sound_buffers[sound_buffer_index], SOUND_BUFFER_SIZE);
locked = false;
}
#ifndef PIMP_MIXER_H
#define PIMP_MIXER_H
#include "pimp_types.h"
#include "config.h"
typedef enum
{
LOOP_TYPE_NONE,
LOOP_TYPE_FORWARD,
LOOP_TYPE_PINGPONG
} pimp_mixer_loop_type;
typedef struct
{
u32 sample_length;
u32 loop_start;
u32 loop_end;
pimp_mixer_loop_type loop_type;
const u8 *sample_data;
u32 sample_cursor;
s32 sample_cursor_delta;
s32 volume;
} pimp_mixer_channel_state;
typedef struct
{
pimp_mixer_channel_state channels[CHANNELS];
/* TODO: any other needed states */
} pimp_mixer;
void pimp_mixer_reset(pimp_mixer *mixer);
void pimp_mixer_mix(pimp_mixer *mixer, s8 *target, int samples);
u32 pimp_mixer_mix_samples(s32 *target, u32 samples, const u8 *sample_data, u32 vol, u32 sample_cursor, s32 sample_cursor_delta);
void pimp_mixer_clip_samples(s8 *target, s32 *source, u32 samples, u32 dc_offs);
#endif /* MIXER_H */
......@@ -5,7 +5,7 @@
#include "pimp_internal.h"
#include "pimp_render.h"
#include "pimp_debug.h"
#include "mixer.h"
#include "pimp_mixer.h"
#include "math.h"
// #define PRINT_PATTERNS
......@@ -19,12 +19,13 @@ STATIC INLINE void set_bpm(pimp_mod_context *ctx, int bpm)
ctx->tick_len = int((SAMPLERATE * 5) * (1 << 8)) / (bpm * 2);
}
void init_pimp_mod_context(pimp_mod_context *ctx, const pimp_module *mod, const u8 *sample_bank)
void init_pimp_mod_context(pimp_mod_context *ctx, const pimp_module *mod, const u8 *sample_bank, pimp_mixer *mixer)
{
assert(ctx != NULL);
ctx->mod = mod;
ctx->sample_bank = sample_bank;
ctx->mixer = mixer;
/* setup default player-state */
ctx->tick_len = 0;
......@@ -97,7 +98,7 @@ void init_pimp_mod_context(pimp_mod_context *ctx, const pimp_module *mod, const
}
#endif
mixer::reset();
pimp_mixer_reset(ctx->mixer);
}
static pimp_callback callback = 0;
......@@ -186,16 +187,16 @@ unsigned eval_vol_env(pimp_channel_state &chan)
return val << 2;
}
void update_row(pimp_mod_context &ctx)
void update_row(pimp_mod_context *ctx)
{
assert(mod != 0);
for (u32 c = 0; c < ctx.mod->channel_count; ++c)
for (u32 c = 0; c < ctx->mod->channel_count; ++c)
{
pimp_channel_state &chan = ctx.channels[c];
volatile mixer::channel_t &mc = mixer::channels[c];
pimp_channel_state &chan = ctx->channels[c];
volatile pimp_mixer_channel_state &mc = ctx->mixer->channels[c];
const pimp_pattern_entry *note = &get_pattern_data(ctx.mod, ctx.curr_pattern)[ctx.curr_row * ctx.mod->channel_count + c];
const pimp_pattern_entry *note = &get_pattern_data(ctx->mod, ctx->curr_pattern)[ctx->curr_row * ctx->mod->channel_count + c];
#ifdef PRINT_PATTERNS
print_pattern_entry(*note);
......@@ -210,9 +211,9 @@ void update_row(pimp_mod_context &ctx)
if (note->instrument > 0)
{
chan.instrument = get_instrument(ctx.mod, note->instrument - 1);
chan.sample = get_sample(ctx.mod, chan.instrument, chan.instrument->sample_map[note->note]);
chan.vol_env = get_vol_env(ctx.mod, chan.instrument);
chan.instrument = get_instrument(ctx->mod, note->instrument - 1);
chan.sample = get_sample(ctx->mod, chan.instrument, chan.instrument->sample_map[note->note]);
chan.vol_env = get_vol_env(ctx->mod, chan.instrument);
chan.vol_env_node = 0;
chan.vol_env_tick = 0;
......@@ -236,15 +237,15 @@ void update_row(pimp_mod_context &ctx)
}
else
{
chan.sample = get_sample(ctx.mod, chan.instrument, chan.instrument->sample_map[note->note]);
chan.sample = get_sample(ctx->mod, chan.instrument, chan.instrument->sample_map[note->note]);
mc.sample_cursor = 0;
mc.sample_data = ctx.sample_bank + chan.sample->data_ptr;
mc.sample_data = ctx->sample_bank + chan.sample->data_ptr;
mc.sample_length = chan.sample->length;
mc.loop_type = (mixer::loop_type_t)chan.sample->loop_type;
mc.loop_type = (pimp_mixer_loop_type)chan.sample->loop_type;
mc.loop_start = chan.sample->loop_start;
mc.loop_end = chan.sample->loop_start + chan.sample->loop_length;
if (ctx.mod->flags & FLAG_LINEAR_PERIODS)
if (ctx->mod->flags & FLAG_LINEAR_PERIODS)
{
chan.period = get_linear_period(((s32)note->note) + chan.sample->rel_note, chan.sample->fine_tune);
}
......@@ -322,12 +323,12 @@ $f0-$ff Tone porta
if (note->note > 0)
{
// no fine tune or relative note here, boooy
if (ctx.mod->flags & FLAG_LINEAR_PERIODS) chan.porta_target = get_linear_period(note->note + chan.sample->rel_note, 0);
if (ctx->mod->flags & FLAG_LINEAR_PERIODS) chan.porta_target = get_linear_period(note->note + chan.sample->rel_note, 0);
else chan.porta_target = get_amiga_period(note->note, 0);
/* clamp porta-target period (should not be done for S3M) */
if (chan.porta_target > ctx.mod->period_high_clamp) chan.porta_target = ctx.mod->period_high_clamp;
if (chan.porta_target < ctx.mod->period_low_clamp) chan.porta_target = ctx.mod->period_low_clamp;
if (chan.porta_target > ctx->mod->period_high_clamp) chan.porta_target = ctx->mod->period_high_clamp;
if (chan.porta_target < ctx->mod->period_low_clamp) chan.porta_target = ctx->mod->period_low_clamp;
}
if (chan.effect_param != 0) chan.porta_speed = chan.effect_param * 4;
break;
......@@ -339,12 +340,12 @@ $f0-$ff Tone porta
if (note->note > 0)
{
// no fine tune or relative note here, boooy
if (ctx.mod->flags & FLAG_LINEAR_PERIODS) chan.porta_target = get_linear_period(note->note + chan.sample->rel_note, 0);
if (ctx->mod->flags & FLAG_LINEAR_PERIODS) chan.porta_target = get_linear_period(note->note + chan.sample->rel_note, 0);
else chan.porta_target = get_amiga_period(note->note, 0);
/* clamp porta-target period (should not be done for S3M) */
if (chan.porta_target > ctx.mod->period_high_clamp) chan.porta_target = ctx.mod->period_high_clamp;
if (chan.porta_target < ctx.mod->period_low_clamp) chan.porta_target = ctx.mod->period_low_clamp;
if (chan.porta_target > ctx->mod->period_high_clamp) chan.porta_target = ctx->mod->period_high_clamp;
if (chan.porta_target < ctx->mod->period_low_clamp) chan.porta_target = ctx->mod->period_low_clamp;
}
if (chan.effect_param & 0xF0)
......@@ -396,9 +397,9 @@ $f0-$ff Tone porta
break;
case EFF_BREAK_ROW:
ctx.curr_order++;
ctx.curr_row = (chan.effect_param >> 4) * 10 + (chan.effect_param & 0xF) - 1;
ctx.curr_pattern = get_pattern(ctx.mod, get_order(ctx.mod, ctx.curr_order));
ctx->curr_order++;
ctx->curr_row = (chan.effect_param >> 4) * 10 + (chan.effect_param & 0xF) - 1;
ctx->curr_pattern = get_pattern(ctx->mod, get_order(ctx->mod, ctx->curr_order));
break;
case EFF_MULTI_FX:
......@@ -407,12 +408,12 @@ $f0-$ff Tone porta
case EFF_AMIGA_FILTER: break;
case EFF_FINE_PORTA_UP:
porta_up(chan, ctx.mod->period_low_clamp);
porta_up(chan, ctx->mod->period_low_clamp);
period_dirty = true;
break;
case EFF_FINE_PORTA_DOWN:
porta_down(chan, ctx.mod->period_high_clamp);
porta_down(chan, ctx->mod->period_high_clamp);
period_dirty = true;
break;
......@@ -443,8 +444,8 @@ $f0-$ff Tone porta
break;
case EFF_TEMPO:
if (note->effect_parameter < 0x20) ctx.curr_tempo = chan.effect_param;
else set_bpm(&ctx, chan.effect_param);
if (note->effect_parameter < 0x20) ctx->curr_tempo = chan.effect_param;
else set_bpm(ctx, chan.effect_param);
break;
/*
......@@ -478,7 +479,7 @@ $f0-$ff Tone porta
if (period_dirty)
{
if (ctx.mod->flags & FLAG_LINEAR_PERIODS)
if (ctx->mod->flags & FLAG_LINEAR_PERIODS)
{
mc.sample_cursor_delta = get_linear_delta(chan.final_period);
}
......@@ -490,7 +491,7 @@ $f0-$ff Tone porta
if (volume_dirty || chan.vol_env != 0)
{
mc.volume = (chan.volume * ctx.global_volume) >> 8;
mc.volume = (chan.volume * ctx->global_volume) >> 8;
if (chan.vol_env != 0) mc.volume = (mc.volume * eval_vol_env(chan)) >> 8;
}
}
......@@ -499,32 +500,32 @@ $f0-$ff Tone porta
iprintf("\n");
#endif
ctx.curr_tick = 0;
ctx.curr_row++;
if (ctx.curr_row == ctx.curr_pattern->row_count)
ctx->curr_tick = 0;
ctx->curr_row++;
if (ctx->curr_row == ctx->curr_pattern->row_count)
{
ctx.curr_row = 0;
ctx.curr_order++;
if (ctx.curr_order >= ctx.mod->order_count) ctx.curr_order = ctx.mod->order_repeat;
ctx.curr_pattern = get_pattern(ctx.mod, get_order(ctx.mod, ctx.curr_order));
ctx->curr_row = 0;