example: add mod
This commit is contained in:
parent
4561bb35f8
commit
6d8b7f282e
24
assert.h
Normal file
24
assert.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(__dreamcast__)
|
||||
#include "sh7091/serial.hpp"
|
||||
#define print__character serial::character
|
||||
#define print__string serial::string
|
||||
#define print__integer serial::integer<uint32_t>
|
||||
#else
|
||||
#error "unknown platform"
|
||||
#endif
|
||||
|
||||
#define assert(b) \
|
||||
do { \
|
||||
if (!(b)) { \
|
||||
print__string(__FILE__); \
|
||||
print__character(':'); \
|
||||
print__integer(__LINE__, ' '); \
|
||||
print__string(__func__); \
|
||||
print__string(": assertion failed: "); \
|
||||
print__string(#b); \
|
||||
print__character('\n'); \
|
||||
while (1); \
|
||||
} \
|
||||
} while (0);
|
6
base.mk
6
base.mk
@ -102,6 +102,12 @@ endef
|
||||
%.vq.o: %.vq
|
||||
$(BUILD_BINARY_O)
|
||||
|
||||
%.mod.h: %.mod
|
||||
$(BUILD_BINARY_H)
|
||||
|
||||
%.mod.o: %.mod
|
||||
$(BUILD_BINARY_O)
|
||||
|
||||
%.o: %.s
|
||||
$(AS) $(AARCH) $(AFLAGS) $(DEBUG) $< -o $@
|
||||
|
||||
|
@ -976,3 +976,32 @@ FOG_OBJ = \
|
||||
|
||||
example/fog.elf: LDSCRIPT = $(LIB)/main.lds
|
||||
example/fog.elf: $(START_OBJ) $(FOG_OBJ)
|
||||
|
||||
BOIDS_OBJ = \
|
||||
example/boids.o \
|
||||
holly/core.o \
|
||||
holly/region_array.o \
|
||||
holly/background.o \
|
||||
holly/ta_fifo_polygon_converter.o \
|
||||
holly/video_output.o \
|
||||
sh7091/serial.o \
|
||||
$(LIBGCC)
|
||||
|
||||
example/boids.elf: LDSCRIPT = $(LIB)/main.lds
|
||||
example/boids.elf: $(START_OBJ) $(BOIDS_OBJ)
|
||||
|
||||
|
||||
MOD_OBJ = \
|
||||
example/mod.o \
|
||||
holly/core.o \
|
||||
holly/region_array.o \
|
||||
holly/background.o \
|
||||
holly/ta_fifo_polygon_converter.o \
|
||||
holly/video_output.o \
|
||||
sh7091/serial.o \
|
||||
mod/mod.o \
|
||||
mod/getfunk/getfunk.mod.o \
|
||||
$(LIBGCC)
|
||||
|
||||
example/mod.elf: LDSCRIPT = $(LIB)/main.lds
|
||||
example/mod.elf: $(START_OBJ) $(MOD_OBJ)
|
||||
|
84
example/mod.cpp
Normal file
84
example/mod.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
#include "aica/aica.hpp"
|
||||
#include "memorymap.hpp"
|
||||
#include "sh7091/serial.hpp"
|
||||
#include "systembus.hpp"
|
||||
#include "systembus_bits.hpp"
|
||||
|
||||
#include "mod/mod.hpp"
|
||||
#include "mod/getfunk/getfunk.mod.h"
|
||||
|
||||
void wait()
|
||||
{
|
||||
uint32_t ffst = system.FFST;
|
||||
while ( ffst::holly_cpu_if_block_internal_write_buffer(ffst)
|
||||
| ffst::holly_g2_if_block_internal_write_buffer(ffst)
|
||||
| ffst::aica_internal_write_buffer(ffst)) {
|
||||
ffst = system.FFST;
|
||||
};
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
serial::init(0);
|
||||
|
||||
const uint8_t * start = reinterpret_cast<uint8_t *>(&_binary_mod_getfunk_getfunk_mod_start);
|
||||
const uint32_t size = reinterpret_cast<uint32_t>(&_binary_mod_getfunk_getfunk_mod_size);
|
||||
|
||||
struct reader r = {
|
||||
.buf = start,
|
||||
.length = (int)size,
|
||||
.ix = 0,
|
||||
};
|
||||
|
||||
struct mod mod;
|
||||
|
||||
parse_mod_file(&r, &mod);
|
||||
|
||||
serial::string(mod.tag, 4);
|
||||
|
||||
serial::integer<uint32_t>(r.ix);
|
||||
serial::integer<uint32_t>(r.ix);
|
||||
serial::integer<uint32_t>(r.ix);
|
||||
|
||||
// reset ARM
|
||||
wait(); aica_sound.common.vreg_armrst = aica::vreg_armrst::ARMRST(1);
|
||||
// disable DSP / ARM / slot access ; enable SH4 access
|
||||
wait(); aica_sound.common.dmea0_mrwinh = aica::dmea0_mrwinh::MRWINH(0b0111);
|
||||
|
||||
volatile uint32_t * slot = reinterpret_cast<volatile uint32_t*>(0xa0700000);
|
||||
for (uint32_t i = 0; i < (sizeof (struct aica_channel)) * 64 / 4; i++) {
|
||||
wait(); slot[i] = 0;
|
||||
}
|
||||
|
||||
volatile uint32_t * dsp = reinterpret_cast<volatile uint32_t*>(0xa0700000 + 0x3000);
|
||||
for (int i = 0; i < 0xb00 / 4; i++) {
|
||||
wait(); dsp[i] = 0;
|
||||
}
|
||||
|
||||
uint32_t * buf32 = (uint32_t *)&start[r.ix];
|
||||
struct sample * sample = &mod.samples[0es);
|
||||
wait(); aica_sound.channel[0].D2R(0x0);
|
||||
wait(); aica_sound.channel[0].D1R(0x0);
|
||||
wait(); aica_sound.channel[0].RR(0x0);
|
||||
wait(); aica_sound.channel[0].AR(0x1f);
|
||||
|
||||
wait(); aica_sound.channel[0].OCT(-2);
|
||||
wait(); aica_sound.channel[0].FNS(0);
|
||||
wait(); aica_sound.channel[0].DISDL(0xf);
|
||||
wait(); aica_sound.channel[0].DIPAN(0x0);
|
||||
|
||||
wait(); aica_sound.channel[0].Q(0b00100);
|
||||
wait(); aica_sound.channel[0].TL(0);
|
||||
wait(); aica_sound.channel[0].LPOFF(1);
|
||||
|
||||
wait(); aica_sound.common.mono_mem8mb_dac18b_ver_mvol =
|
||||
aica::mono_mem8mb_dac18b_ver_mvol::MONO(0) // enable panpots
|
||||
| aica::mono_mem8mb_dac18b_ver_mvol::MEM8MB(0) // 16Mbit SDRAM
|
||||
| aica::mono_mem8mb_dac18b_ver_mvol::DAC18B(0) // 16-bit DAC
|
||||
| aica::mono_mem8mb_dac18b_ver_mvol::MVOL(0xf) // 15/15 volume
|
||||
;
|
||||
|
||||
wait(); aica_sound.channel[0].KYONEX(1);
|
||||
|
||||
while (1);
|
||||
}
|
BIN
mod/getfunk/getfunk.mod
Normal file
BIN
mod/getfunk/getfunk.mod
Normal file
Binary file not shown.
15
mod/getfunk/getfunk.mod.h
Normal file
15
mod/getfunk/getfunk.mod.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern uint32_t _binary_mod_getfunk_getfunk_mod_start __asm("_binary_mod_getfunk_getfunk_mod_start");
|
||||
extern uint32_t _binary_mod_getfunk_getfunk_mod_end __asm("_binary_mod_getfunk_getfunk_mod_end");
|
||||
extern uint32_t _binary_mod_getfunk_getfunk_mod_size __asm("_binary_mod_getfunk_getfunk_mod_size");
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
98
mod/mod.cpp
Normal file
98
mod/mod.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
#include "mod.hpp"
|
||||
#include "assert.h"
|
||||
|
||||
static const uint8_t * reader_s(struct reader * r, int length)
|
||||
{
|
||||
const uint8_t * ptr = &r->buf[r->ix];
|
||||
r->ix += length;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void reader_bytes(struct reader * r, int length, uint8_t * dst)
|
||||
{
|
||||
const uint8_t * ptr = reader_s(r, length);
|
||||
for (int i = 0; i < length; i++)
|
||||
dst[i] = ptr[i];
|
||||
}
|
||||
|
||||
static int reader_u8(struct reader * r)
|
||||
{
|
||||
const uint8_t * ptr = reader_s(r, 1);
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
static int reader_u16(struct reader * r)
|
||||
{
|
||||
const uint8_t * ptr = reader_s(r, 2);
|
||||
int value = (((uint32_t)ptr[0]) << 8) | (((uint32_t)ptr[1]) << 0);
|
||||
return value;
|
||||
}
|
||||
|
||||
static void parse_sample(struct reader * r, struct sample * s)
|
||||
{
|
||||
s->name = reader_s(r, 22);
|
||||
s->length = reader_u16(r);
|
||||
s->nibble = reader_u8(r);
|
||||
s->volume = reader_u8(r);
|
||||
s->repeat_offset = reader_u16(r);
|
||||
s->repeat_length = reader_u16(r);
|
||||
}
|
||||
|
||||
static int parse_num_patterns(uint8_t * table)
|
||||
{
|
||||
int max = 0;
|
||||
for (int i = 0; i < 128; i++) {
|
||||
if ((int)table[i] > max) {
|
||||
max = table[i];
|
||||
}
|
||||
}
|
||||
return max + 1;
|
||||
}
|
||||
|
||||
static void parse_channel(const uint8_t * data, struct channel * c)
|
||||
{
|
||||
uint32_t w = ((uint32_t)data[0] >> 4) & 0xf;
|
||||
uint32_t x = ((uint32_t)data[1]) | (((uint32_t)data[0] & 0xf) << 8);
|
||||
uint32_t y = ((uint32_t)data[2] >> 4) & 0xf;
|
||||
uint32_t z = ((uint32_t)data[3]) | (((uint32_t)data[2] & 0xf) << 8);
|
||||
|
||||
c->sample = (w << 4) | y;
|
||||
c->parameter = x;
|
||||
c->effect = z;
|
||||
}
|
||||
|
||||
static void parse_pattern(struct reader * r, struct pattern * pattern)
|
||||
{
|
||||
const uint8_t * raw_pattern = reader_s(r, 1024);
|
||||
for (int division = 0; division < 64; division++) {
|
||||
int ix = division * 16;
|
||||
parse_channel(&raw_pattern[ix+0 ], &pattern->division[division][0]);
|
||||
parse_channel(&raw_pattern[ix+4 ], &pattern->division[division][1]);
|
||||
parse_channel(&raw_pattern[ix+8 ], &pattern->division[division][2]);
|
||||
parse_channel(&raw_pattern[ix+12], &pattern->division[division][3]);
|
||||
}
|
||||
}
|
||||
|
||||
void parse_mod_file(struct reader * r, struct mod * mod)
|
||||
{
|
||||
mod->title = reader_s(r, 20);
|
||||
|
||||
for (int i = 0; i < 31; i++) {
|
||||
parse_sample(r, &mod->samples[i]);
|
||||
}
|
||||
|
||||
mod->song_positions = reader_u8(r);
|
||||
mod->ignored = reader_u8(r);
|
||||
reader_bytes(r, 128, mod->pattern_table);
|
||||
|
||||
assert(r->ix == 0x438);
|
||||
reader_bytes(r, 4, mod->tag);
|
||||
|
||||
assert(mod->tag[0] == 'M' && mod->tag[1] == '.' &&
|
||||
mod->tag[2] == 'K' && mod->tag[3] == '.');
|
||||
|
||||
int num_patterns = parse_num_patterns(mod->pattern_table);
|
||||
for (int i = 0; i < num_patterns; i++) {
|
||||
parse_pattern(r, &mod->patterns[i]);
|
||||
}
|
||||
}
|
45
mod/mod.hpp
Normal file
45
mod/mod.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
struct sample
|
||||
{
|
||||
const uint8_t * name;
|
||||
int length;
|
||||
int nibble;
|
||||
int volume;
|
||||
int repeat_offset;
|
||||
int repeat_length;
|
||||
};
|
||||
|
||||
struct channel {
|
||||
uint16_t sample;
|
||||
uint16_t parameter;
|
||||
uint16_t effect;
|
||||
uint16_t _pad;
|
||||
};
|
||||
|
||||
struct pattern
|
||||
{
|
||||
struct channel division[64][4];
|
||||
};
|
||||
|
||||
struct mod
|
||||
{
|
||||
const uint8_t * title;
|
||||
struct sample samples[31];
|
||||
int song_positions;
|
||||
int ignored;
|
||||
uint8_t pattern_table[128];
|
||||
uint8_t tag[4];
|
||||
struct pattern patterns[128];
|
||||
};
|
||||
|
||||
struct reader
|
||||
{
|
||||
const uint8_t * buf;
|
||||
const int length;
|
||||
int ix;
|
||||
};
|
||||
|
||||
void parse_mod_file(struct reader * r, struct mod * mod);
|
Loading…
x
Reference in New Issue
Block a user