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

now it kinda plays something ;)

git-svn-id: https://pimpmobile.svn.sourceforge.net/svnroot/pimpmobile/trunk@61 3d5ecaf0-f903-0410-b953-c2c1a4d75763
parent 750d792a
......@@ -24,7 +24,7 @@ float normal_noise()
return r;
}
/* converts all samples to u8-format. yes, this might be the clumsiest routine for this purpose ever written, who cares? */
/* converts a sample to u8-format. yes, this might be the clumsiest routine for this purpose ever written, who cares? */
void convert_sample(sample_header_t *samp)
{
assert(samp != 0);
......@@ -79,6 +79,7 @@ void convert_sample(sample_header_t *samp)
samp->format = SAMPLE_UNSIGNED_8BIT;
}
/* converts all samples to u8-format. */
void convert_samples(module_t *mod)
{
assert(mod != 0);
......@@ -166,12 +167,16 @@ int main(int argc, char *argv[])
printf("converting samples\n");
convert_samples(mod); // convert all samples to unsigned 8bit format
printf("dumping samples\n");
dump_samples(mod); // find any duplicate samples, and merge them
// print_patterns(mod);
// exit(0);
size_t period_pos = filename.rfind(".") + 1;
filename.replace(period_pos, filename.size() - period_pos, "bin");
dump_module(mod, filename.c_str());
}
write_sample_dump("sample_bank.bin"); // dump all samples to file
return 0;
}
......@@ -120,9 +120,10 @@ typedef struct
/*
actual sample-data: NULL/zero length means that sample doesn't exist.
*/
void *waveform; /* pointer to actual sample waveform data */
u32 length;
/*
sample format
*/
......@@ -178,6 +179,11 @@ typedef struct
u8 vibrato_depth;
u8 vibrato_sweep;
sample_vibrato_waveform_t vibrato_waveform;
int rel_ptr; // relative to sample bank
} sample_header_t;
......@@ -337,5 +343,9 @@ module_t *load_module_xm(FILE *fp);
module_t *load_module_mod(FILE *fp);
module_t *load_module_s3m(FILE *fp);
/* dumper */
/* pattern/instrument dumper */
void dump_module(module_t *mod, const char *filename);
/* sample dumper */
void dump_samples(module_t *mod);
void write_sample_dump(const char *filename);
......@@ -77,8 +77,6 @@ module_t *load_module_mod(FILE *fp)
default: return NULL; // not a mod as far as we can see.
}
printf("sig: %c%c%c%c\n", ((char*)&sig)[0], ((char*)&sig)[1], ((char*)&sig)[2], ((char*)&sig)[3]);
printf("chans: %i\n", channels);
module_t *mod = (module_t *)malloc(sizeof(module_t));
if (mod == 0)
......@@ -126,7 +124,6 @@ module_t *load_module_mod(FILE *fp)
rewind(fp);
fread(name, 20, 1, fp);
name[20] = '\0';
printf("name : \"%s\"\n", name);
strcpy(mod->name, name);
mod->channels.resize(channels);
......@@ -176,7 +173,6 @@ module_t *load_module_mod(FILE *fp)
fread(buf, 1, 2, fp);
samp.length = ((buf[0] << 8) | buf[1]) << 1;
// printf("length: %i ", samp.length);
fread(buf, 1, 1, fp);
if (buf[0] > 7) samp.finetune = (buf[0] - 16) << 4;
......@@ -202,7 +198,11 @@ module_t *load_module_mod(FILE *fp)
fread(buf, 1, 1, fp);
mod->order.resize(buf[0]);
if (mod->order.size() > 128) mod->order.resize(128);
if (mod->order.size() > 128)
{
fprintf(stderr, "warning: excessive orders in module, discarding.");
mod->order.resize(128);
}
mod->repeat_pos = 0;
fseek(fp, 1, SEEK_CUR); // discard unused byte (this may be repeat position, but that is impossible to tell)
......@@ -231,7 +231,7 @@ module_t *load_module_mod(FILE *fp)
pattern_entry_t &pe = pat.pattern_data[i * channels + j];
fread(buf, 1, 4, fp);
pe.instrument = (buf[0] & 0x0F0) + (buf[2] >> 4);
pe.note = return_nearest_note(((buf[0] & 0x0F) << 8) + buf[1]) - 12;
pe.note = return_nearest_note(((buf[0] & 0x0F) << 8) + buf[1]); // - 12;
pe.effect_byte = buf[2] & 0xF;
pe.effect_parameter = buf[3];
}
......@@ -249,6 +249,14 @@ module_t *load_module_mod(FILE *fp)
assert(samp.waveform != NULL);
fread(samp.waveform, 1, samp.length, fp);
}
if (samp.length <= 2)
{
free(samp.waveform);
samp.waveform = 0;
samp.length = 0;
}
samp.rel_ptr = -1;
}
// setup default pr channel settings.
......
......@@ -483,6 +483,7 @@ module_t *load_module_xm(FILE *fp)
samp.loop_start = sh.loop_start;
samp.loop_end = sh.loop_start + sh.loop_length;
samp.rel_ptr = -1;
/* IT only */
samp.sustain_loop_type = LOOP_NONE;
......
......@@ -271,7 +271,7 @@ void dump_module(module_t *mod, const char *filename)
for (int i = 0; i < mod->patterns.size(); ++i)
{
pattern_header_t &pat = mod->patterns[i];
// no need for alignment as the struct only contains bytes
pointer_back_map.insert(make_pair(&pat.pattern_data[0], pos));
// write the actual data
......@@ -319,9 +319,77 @@ void dump_module(module_t *mod, const char *filename)
pointer_back_map.insert(make_pair(&mod->instruments[0], pos));
for (int i = 0; i < mod->instruments.size(); ++i)
{
// printf("%s\n", mod->instruments[i].name);
instrument_t &instr = mod->instruments[i];
printf("instrument: %s\n", instr.name);
align(4);
if (&instr.samples[0] != 0) pointer_map.insert(make_pair(&instr.samples[0], pos));
dump_word((unsigned)&instr.samples[0]);
// if (instr.volume_envelope != 0) pointer_map.insert(make_pair(instr.volume_envelope, pos));
dump_word((unsigned)instr.volume_envelope);
// if (instr.panning_envelope != 0) pointer_map.insert(make_pair(instr.panning_envelope, pos));
dump_word((unsigned)instr.panning_envelope);
#if 0
// IT ONLY
if (instr.pitch_envelope != 0) pointer_map.insert(make_pair(instr.pitch_envelope, pos));
dump_word((unsigned)instr.pitch_envelope);
#endif
dump_halfword(instr.fadeout_rate);
dump_halfword(instr.samples.size());
for (int s = 0; s < 120; ++s)
{
dump_byte(instr.sample_map[s]);
}
/*
for (int s = 0; s < instr.samples.size(); ++s)
{
sample_header_t &samp = instr.samples[s];
assert(samp.rel_ptr >= 0);
}
*/
}
// instrument data
for (int i = 0; i < mod->instruments.size(); ++i)
{
instrument_t &instr = mod->instruments[i];
align(4);
pointer_back_map.insert(make_pair(&instr.samples[0], pos));
for (int s = 0; s < instr.samples.size(); ++s)
{
sample_header_t &samp = instr.samples[s];
assert(samp.rel_ptr >= 0);
align(4);
dump_word(samp.rel_ptr);
dump_word(samp.length);
// dump_word(10010);
dump_word(samp.loop_start);
dump_word(samp.loop_end - samp.loop_start);
dump_halfword(samp.finetune);
dump_halfword(samp.sample_note_offset);
dump_byte(samp.default_volume);
dump_byte(samp.loop_type);
dump_byte(samp.default_pan_position);
dump_byte(samp.vibrato_speed);
dump_byte(samp.vibrato_depth);
dump_byte(samp.vibrato_sweep);
dump_byte(samp.vibrato_waveform);
}
// if (&instr.samples[0] != 0) pointer_map.insert(make_pair(&instr.samples[0], pos));
// dump_word((unsigned)&instr.samples[0]);
}
// fixback pointers
for (multimap<void *, unsigned>::iterator it = pointer_map.begin(); it != pointer_map.end(); ++it)
{
......@@ -344,6 +412,12 @@ void dump_module(module_t *mod, const char *filename)
}
FILE *fp = fopen(filename, "wb");
if (!fp)
{
printf("error: failed to open output-file\n");
exit(1);
}
for (unsigned i = 0; i < pos; ++i)
{
fwrite(&data[i], 1, 1, fp);
......
......@@ -67,11 +67,11 @@ $(CONVERTER)::
$(PIMPMOBILE)/lib/libpimpmobile.a::
make -C .. lib/libpimpmobile.a
data.o: sample.raw eye.bin
data.o: sample_bank.bin eye.bin
$(TARGET:.gba=.elf): $(OBJS) $(PIMPMOBILE)/lib/libpimpmobile.a
$(MODULES:.mod=.bin) samples.bin : $(MODULES) $(CONVERTER)
$(MODULES:.mod=.bin) sample_bank.bin : $(MODULES) $(CONVERTER)
$(CONVERTER) $(MODULES)
%.elf:
......
......@@ -7,8 +7,8 @@
.incbin "\filename"
.endm
datafile sample, sample.raw
.global sample_end
sample_end:
datafile sample_bank, sample_bank.bin
.global sample_bank_end
sample_bank_end:
datafile module, eye.bin
......@@ -14,8 +14,8 @@
#include "../src/mixer.h"
#include "../src/config.h"
extern const u8 sample[];
extern const u8 sample_end[];
extern const u8 sample_bank[];
extern const u8 sample_bank_end[];
extern const u8 module[];
......@@ -40,21 +40,7 @@ int main()
BG_COLORS[241] = RGB5(31, 31, 31);
REG_DISPCNT = MODE_0 | BG0_ON;
pimp_init(module, 0);
mixer::sample_t mixer_sample;
mixer_sample.data = sample;
mixer_sample.len = &sample_end[0] - &sample[0];
mixer_sample.loop_type = mixer::LOOP_TYPE_FORWARD;
// mixer_sample.loop_type = mixer::LOOP_TYPE_NONE;
mixer_sample.loop_start = 0xF220;
mixer_sample.loop_end = mixer_sample.loop_start + 0xd76; // (&sample_end[0] - &sample[0]);
mixer::channels[0].sample_cursor = 0;
mixer::channels[0].sample_cursor_delta = 0 << 12;
mixer::channels[0].volume = 255;
mixer::channels[0].sample = &mixer_sample;
pimp_init(module, sample_bank);
SetInterrupt(IE_VBL, vblank);
EnableInterrupt(IE_VBL);
......
......@@ -17,12 +17,14 @@ typedef struct
u32 sustain_loop_start;
u32 sustain_loop_end;
*/
s16 finetune;
s16 rel_note;
u8 volume;
s8 finetune;
// s8 finetune;
u8 loop_type;
u8 pan;
s8 rel_note;
// s8 rel_note;
u8 vibrato_speed;
u8 vibrato_depth;
......@@ -119,7 +121,11 @@ typedef struct
u32 sample_ptr;
u32 volume_envelope_ptr;
u32 panning_envelope_ptr;
#if 0
// IT ONLY (later)
u32 pitch_envelope_ptr;
#endif
u16 volume_fadeout;
......
......@@ -51,24 +51,24 @@ bool detect_loop_event(channel_t &chan, size_t samples)
s32 check_point;
s32 end_sample = chan.sample_cursor + chan.sample_cursor_delta * samples;
switch (chan.sample->loop_type)
switch (chan.loop_type)
{
case LOOP_TYPE_NONE:
check_point = chan.sample->len;
check_point = chan.sample_length;
break;
case LOOP_TYPE_FORWARD:
check_point = chan.sample->loop_end;
check_point = chan.loop_end;
break;
case LOOP_TYPE_PINGPONG:
if (chan.sample_cursor_delta >= 0)
{
// moving forwards through the sample
check_point = chan.sample->loop_end;
check_point = chan.loop_end;
}
else
{
// moving backwards through the sample
check_point = chan.sample->loop_start;
check_point = chan.loop_start;
if (end_sample < (check_point << 12))
{
event_delta = -chan.sample_cursor_delta;
......@@ -93,7 +93,7 @@ bool detect_loop_event(channel_t &chan, size_t samples)
// returns false if we hit sample-end
bool process_loop_event(channel_t &chan)
{
switch (chan.sample->loop_type)
switch (chan.loop_type)
{
case LOOP_TYPE_NONE:
return false;
......@@ -101,28 +101,28 @@ bool process_loop_event(channel_t &chan)
case LOOP_TYPE_FORWARD:
do
{
chan.sample_cursor -= (chan.sample->loop_end - chan.sample->loop_start) << 12;
chan.sample_cursor -= (chan.loop_end - chan.loop_start) << 12;
}
while (chan.sample_cursor >= (chan.sample->loop_end << 12));
while (chan.sample_cursor >= (chan.loop_end << 12));
break;
case LOOP_TYPE_PINGPONG:
do
{
if (chan.sample_cursor_delta >= 0)
{
chan.sample_cursor -= chan.sample->loop_end << 12;
chan.sample_cursor -= chan.loop_end << 12;
chan.sample_cursor = -chan.sample_cursor;
chan.sample_cursor += chan.sample->loop_end << 12;
chan.sample_cursor += chan.loop_end << 12;
}
else
{
chan.sample_cursor -= chan.sample->loop_start << 12;
chan.sample_cursor -= chan.loop_start << 12;
chan.sample_cursor = -chan.sample_cursor;
chan.sample_cursor += chan.sample->loop_start << 12;
chan.sample_cursor += chan.loop_start << 12;
}
chan.sample_cursor_delta = -chan.sample_cursor_delta;
}
while (chan.sample_cursor > (chan.sample->loop_end << 12) || chan.sample_cursor < (chan.sample->loop_start << 12));
while (chan.sample_cursor > (chan.loop_end << 12) || chan.sample_cursor < (chan.loop_start << 12));
break;
}
......@@ -150,15 +150,14 @@ static inline void mix_channel(channel_t &chan, s32 *target, size_t samples)
assert(samples > 0);
/* */
while (samples > 0 && detect_loop_event(chan, samples) == true)
{
DEBUG_COLOR(0, 31, 0);
DEBUG_COLOR(0, 0, 31);
do
{
assert((chan.sample_cursor >> 12) < chan.sample->len);
assert((chan.sample_cursor >> 12) < chan.sample_length);
s32 samp = ((u8*)chan.sample->data)[chan.sample_cursor >> 12];
s32 samp = ((u8*)chan.sample_data)[chan.sample_cursor >> 12];
chan.sample_cursor += chan.sample_cursor_delta;
*target++ += samp * chan.volume;
......@@ -175,16 +174,16 @@ static inline void mix_channel(channel_t &chan, s32 *target, size_t samples)
*target++ += chan.volume * 128;
}
chan.sample = 0;
chan.sample_data = 0;
return;
}
}
DEBUG_COLOR(31, 31, 0);
DEBUG_COLOR(31, 0, 31);
timing_start();
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 = mix_samples(target, samples, chan.sample_data, chan.volume, chan.sample_cursor, chan.sample_cursor_delta);
timing_end();
DEBUG_COLOR(31, 0, 0);
......@@ -194,7 +193,7 @@ void mixer::reset()
{
for (u32 c = 0; c < CHANNELS; ++c)
{
channels[c].sample = 0;
channels[c].sample_data = 0;
channels[c].sample_cursor = 0;
channels[c].sample_cursor_delta = 0;
}
......@@ -206,7 +205,7 @@ void mixer::mix(s8 *target, size_t samples)
{
assert(samples > 0);
DEBUG_COLOR(0, 31, 0);
DEBUG_COLOR(0, 31, 31);
// zero out the sample-buffer
u32 zero = 0;
......@@ -216,7 +215,7 @@ void mixer::mix(s8 *target, size_t samples)
for (u32 c = 0; c < CHANNELS; ++c)
{
channel_t &chan = (channel_t &)channels[c];
if (0 != chan.sample) mix_channel(chan, sound_mix_buffer, samples);
if (0 != chan.sample_data) mix_channel(chan, sound_mix_buffer, samples);
}
dc_offs >>= 8;
DEBUG_COLOR(0, 31, 0);
......
......@@ -14,21 +14,16 @@ namespace mixer
LOOP_TYPE_PINGPONG
} loop_type_t;
typedef struct sample_
typedef struct channel_state_
{
u32 len;
u32 sample_length;
u32 loop_start;
u32 loop_end;
loop_type_t loop_type;
const u8 *data;
} sample_t;
typedef struct channel_state_
{
sample_t *sample;
u32 sample_cursor;
s32 sample_cursor_delta;
u32 volume;
const u8 *sample_data;
u32 sample_cursor;
s32 sample_cursor_delta;
u32 volume;
} channel_t;
extern volatile channel_t channels[CHANNELS];
......
......@@ -43,7 +43,7 @@ u32 curr_tempo = 5;
u32 curr_tick = 0;
pimp_pattern_t *curr_pattern = 0;
const unsigned char *sample_bank;
const unsigned char *pimp_sample_bank;
const pimp_module_t *mod;
......@@ -76,6 +76,17 @@ pimp_channel_t &get_channel(const pimp_module_t *mod, int i)
return ((pimp_channel_t*)((char*)mod + mod->channel_ptr))[i];
}
pimp_instrument_t *get_instrument(const pimp_module_t *mod, int i)
{
return &((pimp_instrument_t*)((char*)mod + mod->instrument_ptr))[i];
}
pimp_sample_t *get_sample(const pimp_module_t *mod, pimp_instrument_t *instr, int i)
{
return &((pimp_sample_t*)((char*)mod + instr->sample_ptr))[i];
}
void print_pattern_entry(const pimp_pattern_entry_t &pe)
{
if (pe.note != 0)
......@@ -109,10 +120,10 @@ void print_pattern(const pimp_module_t *mod, pimp_pattern_t *pat)
}
}
extern "C" void pimp_init(const void *module, const void *sample_bank_in)
extern "C" void pimp_init(const void *module, const void *sample_bank)
{
mod = (const pimp_module_t*)module;
sample_bank = (const u8*)sample_bank_in;
pimp_sample_bank = (const u8*)sample_bank;
/* setup default player-state */
curr_row = 0;
......@@ -125,16 +136,11 @@ extern "C" void pimp_init(const void *module, const void *sample_bank_in)
set_bpm(mod->bpm);
curr_tempo = mod->tempo;
iprintf("\n\n\n%i\n", curr_tick_len);
/* iprintf("\n\nperiod range: %d - %d\n", mod->period_low_clamp, mod->period_high_clamp);
iprintf("orders: %d\nrepeat position: %d\n", mod->order_count, mod->order_repeat);
iprintf("global volume: %d\ntempo: %d\nbpm: %d\n", mod->volume, mod->tempo, mod->bpm); */
/* iprintf("channels: %d\n", mod->channel_count); */
iprintf("channels: %d\n", mod->channel_count);
iprintf("order ptr: %d\n", mod->order_ptr);
/*
for (unsigned i = 0; i < mod->order_count; ++i)
{
......@@ -155,7 +161,14 @@ extern "C" void pimp_init(const void *module, const void *sample_bank_in)
}
if (mod->flags & FLAG_LINEAR_PERIODS) iprintf("LINEAR\n");
for (unsigned i = 0; i < mod->instrument_count; ++i)
{
pimp_instrument_t *instr = get_instrument(mod, i);
iprintf("%d ", instr->sample_count);
iprintf("%d\n", instr->sample_map[3]);
}
u32 zero = 0;
CpuFastSet(&zero, &sound_buffers[0][0], DMA_SRC_FIXED | ((SOUND_BUFFER_SIZE / 4) * 2));
REG_SOUNDCNT_H = SNDA_VOL_100 | SNDA_L_ENABLE | SNDA_R_ENABLE | SNDA_RESET_FIFO;
......@@ -237,14 +250,19 @@ void update_row()
pimp_channel_state_t &chan = channels[c];
const pimp_pattern_entry_t *note = &get_pattern_data(mod, curr_pattern)[curr_row * mod->channel_count + c];
// unsigned instr = mod->curr_pattern[mod->row][c].sample;
// print_pattern_entry(*note);
chan.effect = note->effect_byte;
// NOTE ON !
if (note->instrument > 0)
{
pimp_instrument_t *instr = get_instrument(mod, note->instrument - 1);
int sample_index = instr->sample_map[note->note];
if (sample_index == 0) continue;
pimp_sample_t *samp = get_sample(mod, instr, sample_index - 1);
// iprintf("samp: %i\n", samp->data_ptr);
int period, delta;
if (mod->flags & FLAG_LINEAR_PERIODS)
{
......@@ -262,7 +280,8 @@ void update_row()
mixer::channels[c].sample_cursor = 0;
mixer::channels[c].sample_cursor_delta = delta;
mixer::channels[c].volume = 255;
mixer::channels[c].sample = mixer::channels[0].sample;
mixer::channels[c].sample_data = pimp_sample_bank + samp->data_ptr;
mixer::channels[c].sample_length = samp->length;
}
switch (chan.effect)
......@@ -378,7 +397,9 @@ extern "C" void pimp_frame()
if (!samples_left) break;
DEBUG_COLOR(0, 0, 31);
update_tick();
DEBUG_COLOR(31, 31, 31);
// printf("%d %d %d %d\n", mod->bpm, curr_row, curr_order, curr_tick);
// fixed point tick length
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment