example: reorganize aica examples
This commit is contained in:
parent
60d7dd8c1c
commit
dcffc7854e
1
Makefile
1
Makefile
@ -13,6 +13,7 @@ include ip.mk
|
||||
|
||||
include example/example.mk
|
||||
include example/bsp/bsp.mk
|
||||
include example/aica/aica.mk
|
||||
include chess/chess.mk
|
||||
include text_editor/text_editor.mk
|
||||
|
||||
|
37
example/aica/aica.mk
Normal file
37
example/aica/aica.mk
Normal file
@ -0,0 +1,37 @@
|
||||
AICA_OBJ = \
|
||||
example/aica/aica.o \
|
||||
sh7091/serial.o \
|
||||
example/arm/channel.bin.o
|
||||
|
||||
example/aica/aica.elf: LDSCRIPT = $(LIB)/main.lds
|
||||
example/aica/aica.elf: $(START_OBJ) $(AICA_OBJ)
|
||||
|
||||
AICA_XM_OBJ = \
|
||||
example/aica/aica_xm.o \
|
||||
sh7091/serial.o \
|
||||
example/arm/xm.bin.o
|
||||
|
||||
example/aica/aica_xm.elf: LDSCRIPT = $(LIB)/main.lds
|
||||
example/aica/aica_xm.elf: $(START_OBJ) $(AICA_XM_OBJ)
|
||||
|
||||
AICA_GDROM_OBJ = \
|
||||
example/aica/aica_gdrom.o \
|
||||
sh7091/serial.o \
|
||||
example/arm/sh4_interrupt.bin.o
|
||||
|
||||
example/aica/aica_gdrom.elf: LDSCRIPT = $(LIB)/main.lds
|
||||
example/aica/aica_gdrom.elf: $(START_OBJ) $(AICA_GDROM_OBJ)
|
||||
|
||||
AICA_GDROM_DFT_OBJ = \
|
||||
example/aica/aica_gdrom_dft.o \
|
||||
holly/core.o \
|
||||
holly/region_array.o \
|
||||
holly/background.o \
|
||||
holly/ta_fifo_polygon_converter.o \
|
||||
holly/video_output.o \
|
||||
sh7091/serial.o \
|
||||
example/arm/sh4_interrupt.bin.o \
|
||||
$(LIBGCC)
|
||||
|
||||
example/aica/aica_gdrom_dft.elf: LDSCRIPT = $(LIB)/main.lds
|
||||
example/aica/aica_gdrom_dft.elf: $(START_OBJ) $(AICA_GDROM_DFT_OBJ)
|
65
example/aica/aica_xm.cpp
Normal file
65
example/aica/aica_xm.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
#include "memorymap.hpp"
|
||||
#include "sh7091/serial.hpp"
|
||||
#include "systembus.hpp"
|
||||
#include "systembus_bits.hpp"
|
||||
#include "aica/aica.hpp"
|
||||
|
||||
extern void * _binary_start __asm("_binary_example_arm_xm_bin_start");
|
||||
extern void * _binary_size __asm("_binary_example_arm_xm_bin_size");
|
||||
|
||||
void wait()
|
||||
{
|
||||
while (ffst::aica_internal_write_buffer(system.FFST));
|
||||
}
|
||||
|
||||
void wait_read()
|
||||
{
|
||||
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()
|
||||
{
|
||||
const uint32_t * binary = reinterpret_cast<uint32_t *>(&_binary_start);
|
||||
const uint32_t binary_size = reinterpret_cast<uint32_t>(&_binary_size);
|
||||
|
||||
wait(); aica_sound.common.vreg_armrst = aica::vreg_armrst::ARMRST(1);
|
||||
wait(); aica_sound.common.dmea0_mrwinh = aica::dmea0_mrwinh::MRWINH(0b0111);
|
||||
for (uint32_t i = 0; i < binary_size / 4; i++) {
|
||||
// copy
|
||||
while (aica_wave_memory[i] != binary[i]) {
|
||||
wait();
|
||||
aica_wave_memory[i] = binary[i];
|
||||
}
|
||||
}
|
||||
wait(); aica_sound.common.dmea0_mrwinh = aica::dmea0_mrwinh::MRWINH(0b0001);
|
||||
wait(); aica_sound.common.vreg_armrst = aica::vreg_armrst::ARMRST(0);
|
||||
|
||||
wait(); aica_sound.common.afsel_mslc_mobuf = aica::afsel_mslc_mobuf::MSLC(0);
|
||||
serial::string("mrwinh: ");
|
||||
wait_read();
|
||||
serial::integer<uint8_t>(aica_sound.common.MRWINH());
|
||||
while (1) {
|
||||
wait_read();
|
||||
serial::string("sgc: ");
|
||||
serial::integer<uint8_t>(aica_sound.common.SGC(), ' ');
|
||||
serial::string("; ca: ");
|
||||
serial::integer<uint8_t>(aica_sound.common.CA(), ' ');
|
||||
serial::string("; eg: ");
|
||||
serial::integer<uint8_t>(aica_sound.common.EG(), ' ');
|
||||
serial::string("; lp: ");
|
||||
serial::integer<uint8_t>(aica_sound.common.LP(), ' ');
|
||||
serial::character('\n');
|
||||
for (int i = 0; i < 10000000; i++) {
|
||||
asm volatile ("nop");
|
||||
}
|
||||
serial::integer<uint32_t>(aica_wave_memory[0], ' ');
|
||||
serial::integer<uint32_t>(aica_wave_memory[1], '\n');
|
||||
}
|
||||
|
||||
while (1);
|
||||
}
|
@ -25,6 +25,9 @@ channel.elf: start.o channel.o audio.pcm.o
|
||||
sh4_interrupt.elf: LDSCRIPT = main.lds
|
||||
sh4_interrupt.elf: start.o sh4_interrupt.o
|
||||
|
||||
xm.elf: LDSCRIPT = main.lds
|
||||
xm.elf: start.o xm.o audio.pcm.o
|
||||
|
||||
clean:
|
||||
find -P \
|
||||
-regextype posix-egrep \
|
||||
|
75
example/arm/xm.cpp
Normal file
75
example/arm/xm.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
#include "aica/aica.hpp"
|
||||
|
||||
extern void * _sine_start __asm("_binary_audio_pcm_start");
|
||||
|
||||
extern volatile uint32_t dram[0x200000] __asm("dram");
|
||||
|
||||
extern "C"
|
||||
void main()
|
||||
{
|
||||
const uint32_t sine_addr = reinterpret_cast<uint32_t>(&_sine_start);
|
||||
|
||||
volatile uint32_t * slot = reinterpret_cast<volatile uint32_t*>(0x00800000);
|
||||
for (uint32_t i = 0; i < (sizeof (struct aica_channel)) * 64 / 4; i++) {
|
||||
slot[i] = 0;
|
||||
}
|
||||
|
||||
volatile uint32_t * dsp = reinterpret_cast<volatile uint32_t*>(0x00803000);
|
||||
for (int i = 0; i < 0xb00 / 4; i++) {
|
||||
dsp[i] = 0;
|
||||
}
|
||||
|
||||
aica_sound.channel[0].KYONB(1);
|
||||
aica_sound.channel[0].LPCTL(1);
|
||||
aica_sound.channel[0].PCMS(0);
|
||||
aica_sound.channel[0].LSA(0);
|
||||
aica_sound.channel[0].LEA(128);
|
||||
aica_sound.channel[0].D2R(0x0);
|
||||
aica_sound.channel[0].D1R(0x0);
|
||||
aica_sound.channel[0].RR(0x0);
|
||||
aica_sound.channel[0].AR(0x1f);
|
||||
|
||||
aica_sound.channel[0].OCT(0);
|
||||
aica_sound.channel[0].FNS(0);
|
||||
aica_sound.channel[0].DISDL(0xf);
|
||||
aica_sound.channel[0].DIPAN(0x0);
|
||||
|
||||
aica_sound.channel[0].Q(0b00100);
|
||||
aica_sound.channel[0].TL(0);
|
||||
aica_sound.channel[0].LPOFF(1);
|
||||
|
||||
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
|
||||
;
|
||||
|
||||
uint32_t segment = 0;
|
||||
|
||||
dram[0] = 0x11223344;
|
||||
dram[1] = sine_addr;
|
||||
constexpr uint32_t timer_a_interrupt = (1 << 6);
|
||||
aica_sound.common.scire = timer_a_interrupt;
|
||||
uint32_t next_sa = sine_addr;
|
||||
bool started = 0;
|
||||
|
||||
while (1) {
|
||||
if (!started || (aica_sound.common.SCIPD() & timer_a_interrupt)) {
|
||||
aica_sound.channel[0].SA(next_sa);
|
||||
aica_sound.common.tactl_tima =
|
||||
aica::tactl_tima::TACTL(0) // increment once every 128 samples
|
||||
| aica::tactl_tima::TIMA(256 - 128) // interrupt after 128 counts
|
||||
;
|
||||
|
||||
if (!started) { aica_sound.channel[0].KYONEX(1); started = 1; }
|
||||
|
||||
aica_sound.common.scire = timer_a_interrupt;
|
||||
dram[1] = next_sa;
|
||||
|
||||
segment += 1;
|
||||
if (segment >= 3440) segment = 0;
|
||||
next_sa = sine_addr + (128 * 2) * segment;
|
||||
}
|
||||
}
|
||||
}
|
@ -502,37 +502,6 @@ GDROM_JVM_BOOT_OBJ = \
|
||||
example/gdrom_jvm_boot.elf: LDSCRIPT = $(LIB)/alt.lds
|
||||
example/gdrom_jvm_boot.elf: $(START_OBJ) $(GDROM_JVM_BOOT_OBJ)
|
||||
|
||||
|
||||
AICA_OBJ = \
|
||||
example/aica.o \
|
||||
sh7091/serial.o \
|
||||
example/arm/channel.bin.o
|
||||
|
||||
example/aica.elf: LDSCRIPT = $(LIB)/main.lds
|
||||
example/aica.elf: $(START_OBJ) $(AICA_OBJ)
|
||||
|
||||
AICA_GDROM_OBJ = \
|
||||
example/aica_gdrom.o \
|
||||
sh7091/serial.o \
|
||||
example/arm/sh4_interrupt.bin.o
|
||||
|
||||
example/aica_gdrom.elf: LDSCRIPT = $(LIB)/main.lds
|
||||
example/aica_gdrom.elf: $(START_OBJ) $(AICA_GDROM_OBJ)
|
||||
|
||||
AICA_GDROM_DFT_OBJ = \
|
||||
example/aica_gdrom_dft.o \
|
||||
holly/core.o \
|
||||
holly/region_array.o \
|
||||
holly/background.o \
|
||||
holly/ta_fifo_polygon_converter.o \
|
||||
holly/video_output.o \
|
||||
sh7091/serial.o \
|
||||
example/arm/sh4_interrupt.bin.o \
|
||||
$(LIBGCC)
|
||||
|
||||
example/aica_gdrom_dft.elf: LDSCRIPT = $(LIB)/main.lds
|
||||
example/aica_gdrom_dft.elf: $(START_OBJ) $(AICA_GDROM_DFT_OBJ)
|
||||
|
||||
MAC_SATURATION_OBJ = \
|
||||
example/mac_saturation.o \
|
||||
example/macl_saturation.o \
|
||||
|
322
xm/debug.c
Normal file
322
xm/debug.c
Normal file
@ -0,0 +1,322 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "xm.h"
|
||||
|
||||
int read_file(const char * filename, void ** buf, uint32_t * size_out)
|
||||
{
|
||||
FILE * file = fopen(filename, "rb");
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, "fopen(\"%s\", \"rb\"): %s\n", filename, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret;
|
||||
ret = fseek(file, 0L, SEEK_END);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "fseek(SEEK_END)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
long offset = ftell(file);
|
||||
if (offset < 0) {
|
||||
fprintf(stderr, "ftell");
|
||||
return -1;
|
||||
}
|
||||
size_t size = offset;
|
||||
|
||||
ret = fseek(file, 0L, SEEK_SET);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "fseek(SEEK_SET)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "read_file: %s size %ld\n", filename, size);
|
||||
*buf = (uint8_t *)malloc(size);
|
||||
size_t fread_size = fread(*buf, 1, size, file);
|
||||
if (fread_size != size) {
|
||||
fprintf(stderr, "fread `%s` short read: %d ; expected: %d\n", filename, (int)fread_size, (int)size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = fclose(file);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "fclose");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*size_out = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int s16(void * buf)
|
||||
{
|
||||
uint8_t * b = (uint8_t *)buf;
|
||||
int16_t v = (b[0] << 0) | (b[1] << 8);
|
||||
return v;
|
||||
}
|
||||
|
||||
int s32(void * buf)
|
||||
{
|
||||
uint8_t * b = (uint8_t *)buf;
|
||||
int32_t v = (b[0] << 0) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
|
||||
return v;
|
||||
}
|
||||
|
||||
void print_chars(int8_t * chars, int length, const char * end)
|
||||
{
|
||||
for (int i = 0; i < length; i++) {
|
||||
int8_t c = chars[i];
|
||||
if (c >= 0x20 && c <= 0x7e) {
|
||||
fputc(c, stdout);
|
||||
} else {
|
||||
printf("\\x%02x", c);
|
||||
}
|
||||
}
|
||||
if (end != NULL)
|
||||
fputs(end, stdout);
|
||||
}
|
||||
|
||||
void debug_header(void * buf)
|
||||
{
|
||||
xm_header_t * header = (xm_header_t *)buf;
|
||||
printf("header:\n");
|
||||
printf(" id_text: '");
|
||||
print_chars(header->id_text, 17, "'\n");
|
||||
printf(" module_name: '");
|
||||
print_chars(header->module_name, 20, "'\n");
|
||||
printf(" xm_type: 0x%02x\n", header->xm_type);
|
||||
printf(" tracker_name: '");
|
||||
print_chars(header->tracker_name, 20, "'\n");
|
||||
printf(" version_number: 0x%04x\n", s16(&header->version_number));
|
||||
printf(" header_size: %d\n", s32(&header->header_size));
|
||||
printf(" song_length: %d\n", s16(&header->song_length));
|
||||
printf(" restart_position: %d\n", s16(&header->restart_position));
|
||||
printf(" number_of_channels: %d\n", s16(&header->number_of_channels));
|
||||
printf(" number_of_patterns: %d\n", s16(&header->number_of_patterns));
|
||||
printf(" number_of_instruments: %d\n", s16(&header->number_of_instruments));
|
||||
printf(" flags: %d\n", s16(&header->flags));
|
||||
printf(" default_tempo: %d\n", s16(&header->default_tempo));
|
||||
printf(" default_bpm: %d\n", s16(&header->default_bpm));
|
||||
}
|
||||
|
||||
static xm_pattern_format_t column[8];
|
||||
|
||||
void debug_pattern_format(int note_ix, xm_pattern_format_t * pf)
|
||||
{
|
||||
/*
|
||||
printf("note[%d]\n", note_ix);
|
||||
printf(" note: %d\n", pf->note);
|
||||
printf(" instrument: %d\n", pf->instrument);
|
||||
printf(" volume_column_byte: %d\n", pf->volume_column_byte);
|
||||
printf(" effect_type: %d\n", pf->effect_type);
|
||||
printf(" effect_parameter: %d\n", pf->effect_parameter);
|
||||
*/
|
||||
column[note_ix & 7] = *pf;
|
||||
if ((note_ix & 7) == 7) {
|
||||
printf("%3d |", note_ix / 8);
|
||||
for (int i = 0; i < 8; i++)
|
||||
printf(" n:%2d i:%2d |",
|
||||
column[i].note, column[i].instrument);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void debug_pattern(xm_pattern_header_t * pattern_header)
|
||||
{
|
||||
printf(" | channel 0 | channel 1 | channel 2 | channel 3 | channel 4 | channel 5 | channel 6 | channel 7 |\n");
|
||||
uint8_t * pattern = (uint8_t *)(((ptrdiff_t)pattern_header) + s32(&pattern_header->pattern_header_length));
|
||||
int ix = 0;
|
||||
int note_ix = 0;
|
||||
while (ix < s16(&pattern_header->packed_pattern_data_size)) {
|
||||
int p = pattern[ix];
|
||||
if (p & 0x80) {
|
||||
ix += 1;
|
||||
xm_pattern_format_t pf = {};
|
||||
if (p & (1 << 0))
|
||||
pf.note = pattern[ix++];
|
||||
if (p & (1 << 1))
|
||||
pf.instrument = pattern[ix++];
|
||||
if (p & (1 << 2))
|
||||
pf.volume_column_byte = pattern[ix++];
|
||||
if (p & (1 << 3))
|
||||
pf.effect_type = pattern[ix++];
|
||||
if (p & (1 << 4))
|
||||
pf.effect_parameter = pattern[ix++];
|
||||
debug_pattern_format(note_ix, &pf);
|
||||
} else {
|
||||
xm_pattern_format_t * pf = (xm_pattern_format_t *)&pattern[ix];
|
||||
debug_pattern_format(note_ix, pf);
|
||||
ix += 5;
|
||||
}
|
||||
note_ix += 1;
|
||||
}
|
||||
assert(ix == s16(&pattern_header->packed_pattern_data_size));
|
||||
}
|
||||
|
||||
int debug_pattern_headers(void * buf)
|
||||
{
|
||||
xm_header_t * header = (xm_header_t *)buf;
|
||||
int pattern_header_offset = s32(&header->header_size) + (offsetof (struct xm_header, header_size));
|
||||
|
||||
for (int i = 0; i < s16(&header->number_of_patterns); i++) {
|
||||
xm_pattern_header_t * pattern_header = (xm_pattern_header_t *)(((ptrdiff_t)buf) + pattern_header_offset);
|
||||
|
||||
printf("pattern_header[%d]:\n", i);
|
||||
printf(" pattern_header_length: %d\n", s32(&pattern_header->pattern_header_length));
|
||||
printf(" packing_type: %d\n", pattern_header->packing_type);
|
||||
printf(" number_of_rows_in_pattern: %d\n", s16(&pattern_header->number_of_rows_in_pattern));
|
||||
printf(" packed_pattern_data_size: %d\n", s16(&pattern_header->packed_pattern_data_size));
|
||||
//debug_pattern(pattern_header);
|
||||
pattern_header_offset += s32(&pattern_header->pattern_header_length) + s16(&pattern_header->packed_pattern_data_size);
|
||||
}
|
||||
return pattern_header_offset;
|
||||
}
|
||||
|
||||
void write_file(const char * filename, void * buf, int size)
|
||||
{
|
||||
printf("write %s\n", filename);
|
||||
FILE * file = fopen(filename, "wb");
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, "fopen(\"%s\", \"wb\"): %s\n", filename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
size_t write = fwrite(buf, 1, size, file);
|
||||
assert(write == size);
|
||||
|
||||
int ret = fclose(file);
|
||||
assert(ret == 0);
|
||||
}
|
||||
|
||||
int saturation16(int v)
|
||||
{
|
||||
/*
|
||||
if (v > 32767)
|
||||
return 32767;
|
||||
if (v < -32768)
|
||||
return -32768;
|
||||
*/
|
||||
return v;
|
||||
}
|
||||
|
||||
int saturation8(int v)
|
||||
{
|
||||
/*
|
||||
if (v > 127)
|
||||
return 127;
|
||||
if (v < -128)
|
||||
return -128;
|
||||
*/
|
||||
return v;
|
||||
}
|
||||
|
||||
void dump_sample(void * buf, int offset, int sample_ix, xm_sample_header_t * sample_header)
|
||||
{
|
||||
assert(sample_header->sample_data_type == 0);
|
||||
int old = 0;
|
||||
int size = s32(&sample_header->sample_length);
|
||||
printf("%d offset %d\n", sample_ix, offset);
|
||||
if (sample_header->type & (1 << 4)) { // 16-bit samples
|
||||
int num_samples = size / 2;
|
||||
int old = 0;
|
||||
int16_t out[num_samples];
|
||||
int16_t * in = (int16_t *)(((ptrdiff_t)buf) + offset);
|
||||
for (int i = 0; i < num_samples; i++) {
|
||||
old += in[i];
|
||||
out[i] = saturation16(old);
|
||||
}
|
||||
char filename[64];
|
||||
snprintf(filename, 64, "sample%03d.s16le.pcm", sample_ix);
|
||||
write_file(filename, out, size);
|
||||
|
||||
} else { // 8-bit
|
||||
int num_samples = size;
|
||||
int old = 0;
|
||||
int8_t out[num_samples];
|
||||
int8_t * in = (int8_t *)(((ptrdiff_t)buf) + offset);
|
||||
for (int i = 0; i < num_samples; i++) {
|
||||
old += in[i];
|
||||
out[i] = old;
|
||||
}
|
||||
char filename[64];
|
||||
snprintf(filename, 64, "sample%03d.s8.pcm", sample_ix);
|
||||
write_file(filename, out, size);
|
||||
}
|
||||
}
|
||||
|
||||
int debug_samples(void * buf, int offset, int instrument_ix, int number_of_samples)
|
||||
{
|
||||
xm_sample_header_t * sample_header[number_of_samples];
|
||||
printf("A offset %d\n", offset);
|
||||
for (int i = 0; i < number_of_samples; i++) {
|
||||
sample_header[i] = (xm_sample_header_t *)(((ptrdiff_t)buf) + offset);
|
||||
printf(" sample header %d offset %d\n", i, offset);
|
||||
printf(" sample[%d]\n", i);
|
||||
printf(" sample_length: %d\n", s32(&sample_header[i]->sample_length));
|
||||
printf(" sample_loop_start: %d\n", s32(&sample_header[i]->sample_loop_start));
|
||||
printf(" sample_loop_length: %d\n", s32(&sample_header[i]->sample_loop_length));
|
||||
printf(" volume: %d\n", sample_header[i]->volume);
|
||||
printf(" finetune: %d\n", sample_header[i]->finetune);
|
||||
printf(" type: %d\n", sample_header[i]->type);
|
||||
printf(" panning: %d\n", sample_header[i]->panning);
|
||||
printf(" relative_note_number: %d\n", sample_header[i]->relative_note_number);
|
||||
printf(" sample_data_type: %d\n", sample_header[i]->sample_data_type);
|
||||
printf(" sample_name: '");
|
||||
print_chars(sample_header[i]->sample_name, 22, "'\n");
|
||||
offset += (sizeof (xm_sample_header_t));
|
||||
}
|
||||
|
||||
printf("B offset %d\n", offset);
|
||||
for (int i = 0; i < number_of_samples; i++) {
|
||||
if (s32(&sample_header[i]->sample_length) > 0)
|
||||
dump_sample(buf, offset, instrument_ix, sample_header[i]);
|
||||
offset += s32(&sample_header[i]->sample_length);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
int debug_instruments(void * buf, int offset)
|
||||
{
|
||||
xm_header_t * header = (xm_header_t *)buf;
|
||||
|
||||
for (int i = 0; i < s16(&header->number_of_instruments); i++) {
|
||||
printf("instrument offset %d: %d\n", i, offset);
|
||||
xm_instrument_header_t * instrument_header = (xm_instrument_header_t *)(((ptrdiff_t)buf) + offset);
|
||||
|
||||
printf("instrument[%d]\n", i);
|
||||
printf(" instrument_size: %d\n", s32(&instrument_header->instrument_size));
|
||||
printf(" instrument_name: '");
|
||||
print_chars(instrument_header->instrument_name, 22, "'\n");
|
||||
printf(" instrument_type: %d\n", instrument_header->instrument_type);
|
||||
printf(" number_of_samples: %d\n", s16(&instrument_header->number_of_samples));
|
||||
|
||||
offset += s32(&instrument_header->instrument_size);
|
||||
printf("this offset %d\n", offset);
|
||||
|
||||
if (s16(&instrument_header->number_of_samples) > 0) {
|
||||
printf(" sample_header_size: %d\n", s32(&instrument_header->sample_header_size));
|
||||
|
||||
offset = debug_samples(buf, offset, i, s16(&instrument_header->number_of_samples));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
assert(argc == 2);
|
||||
const char * filename = argv[1];
|
||||
|
||||
void * buf;
|
||||
uint32_t size;
|
||||
int res = read_file(filename, &buf, &size);
|
||||
if (res != 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
debug_header(buf);
|
||||
int end_of_patterns = debug_pattern_headers(buf);
|
||||
debug_instruments(buf, end_of_patterns);
|
||||
}
|
BIN
xm/milkypack01.xm
Normal file
BIN
xm/milkypack01.xm
Normal file
Binary file not shown.
1
xm/tune.txt
Normal file
1
xm/tune.txt
Normal file
@ -0,0 +1 @@
|
||||
11025 F-4
|
141
xm/xm.h
Normal file
141
xm/xm.h
Normal file
@ -0,0 +1,141 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct __attribute__((packed)) xm_header {
|
||||
int8_t id_text[17];
|
||||
int8_t module_name[20];
|
||||
uint8_t xm_type;
|
||||
int8_t tracker_name[20];
|
||||
int16_t version_number;
|
||||
int32_t header_size;
|
||||
int16_t song_length;
|
||||
int16_t restart_position;
|
||||
int16_t number_of_channels;
|
||||
int16_t number_of_patterns;
|
||||
int16_t number_of_instruments;
|
||||
int16_t flags;
|
||||
int16_t default_tempo;
|
||||
int16_t default_bpm;
|
||||
uint8_t pattern_order_table[];
|
||||
} xm_header_t;
|
||||
|
||||
static_assert((offsetof (struct xm_header, id_text)) == 0);
|
||||
static_assert((offsetof (struct xm_header, module_name)) == 17);
|
||||
static_assert((offsetof (struct xm_header, xm_type)) == 37);
|
||||
static_assert((offsetof (struct xm_header, tracker_name)) == 38);
|
||||
static_assert((offsetof (struct xm_header, version_number)) == 58);
|
||||
static_assert((offsetof (struct xm_header, header_size)) == 60);
|
||||
static_assert((offsetof (struct xm_header, song_length)) == 64);
|
||||
static_assert((offsetof (struct xm_header, restart_position)) == 66);
|
||||
static_assert((offsetof (struct xm_header, number_of_channels)) == 68);
|
||||
static_assert((offsetof (struct xm_header, number_of_patterns)) == 70);
|
||||
static_assert((offsetof (struct xm_header, number_of_instruments)) == 72);
|
||||
static_assert((offsetof (struct xm_header, flags)) == 74);
|
||||
static_assert((offsetof (struct xm_header, default_tempo)) == 76);
|
||||
static_assert((offsetof (struct xm_header, default_bpm)) == 78);
|
||||
static_assert((offsetof (struct xm_header, pattern_order_table)) == 80);
|
||||
|
||||
typedef struct __attribute__((packed)) xm_pattern_header {
|
||||
int32_t pattern_header_length;
|
||||
int8_t packing_type;
|
||||
int16_t number_of_rows_in_pattern;
|
||||
int16_t packed_pattern_data_size;
|
||||
//int8_t packed_pattern_data[];
|
||||
} xm_pattern_header_t;
|
||||
|
||||
static_assert((offsetof (struct xm_pattern_header, pattern_header_length)) == 0);
|
||||
static_assert((offsetof (struct xm_pattern_header, packing_type)) == 4);
|
||||
static_assert((offsetof (struct xm_pattern_header, number_of_rows_in_pattern)) == 5);
|
||||
static_assert((offsetof (struct xm_pattern_header, packed_pattern_data_size)) == 7);
|
||||
//static_assert((offsetof (struct xm_pattern_header, packed_pattern_data)) == 9);
|
||||
|
||||
typedef struct __attribute__((packed)) xm_instrument_header {
|
||||
int32_t instrument_size;
|
||||
int8_t instrument_name[22];
|
||||
uint8_t instrument_type;
|
||||
int16_t number_of_samples;
|
||||
int32_t sample_header_size;
|
||||
uint8_t sample_keymap_assignments[96];
|
||||
int16_t points_for_volume_envelope[24];
|
||||
int16_t points_for_panning_envelope[24];
|
||||
int8_t number_of_volume_points;
|
||||
int8_t number_of_panning_points;
|
||||
int8_t volume_sustain_point;
|
||||
int8_t volume_loop_start_point;
|
||||
int8_t volume_loop_end_point;
|
||||
int8_t panning_sustain_point;
|
||||
int8_t panning_loop_start_point;
|
||||
int8_t panning_loop_end_point;
|
||||
int8_t volume_type;
|
||||
int8_t panning_type;
|
||||
int8_t vibrato_type;
|
||||
int8_t vibrato_sweep;
|
||||
int8_t vibrato_depth;
|
||||
int8_t vibrato_rate;
|
||||
int8_t volume_fadeout;
|
||||
} xm_instrument_header_t;
|
||||
|
||||
static_assert((offsetof (struct xm_instrument_header, instrument_size)) == 0);
|
||||
static_assert((offsetof (struct xm_instrument_header, instrument_name)) == 4);
|
||||
static_assert((offsetof (struct xm_instrument_header, instrument_type)) == 26);
|
||||
static_assert((offsetof (struct xm_instrument_header, number_of_samples)) == 27);
|
||||
static_assert((offsetof (struct xm_instrument_header, sample_header_size)) == 29);
|
||||
static_assert((offsetof (struct xm_instrument_header, sample_keymap_assignments)) == 33);
|
||||
static_assert((offsetof (struct xm_instrument_header, points_for_volume_envelope)) == 129);
|
||||
static_assert((offsetof (struct xm_instrument_header, points_for_panning_envelope)) == 177);
|
||||
static_assert((offsetof (struct xm_instrument_header, number_of_volume_points)) == 225);
|
||||
static_assert((offsetof (struct xm_instrument_header, number_of_panning_points)) == 226);
|
||||
static_assert((offsetof (struct xm_instrument_header, volume_sustain_point)) == 227);
|
||||
static_assert((offsetof (struct xm_instrument_header, volume_loop_start_point)) == 228);
|
||||
static_assert((offsetof (struct xm_instrument_header, volume_loop_end_point)) == 229);
|
||||
static_assert((offsetof (struct xm_instrument_header, panning_sustain_point)) == 230);
|
||||
static_assert((offsetof (struct xm_instrument_header, panning_loop_start_point)) == 231);
|
||||
static_assert((offsetof (struct xm_instrument_header, panning_loop_end_point)) == 232);
|
||||
static_assert((offsetof (struct xm_instrument_header, volume_type)) == 233);
|
||||
static_assert((offsetof (struct xm_instrument_header, panning_type)) == 234);
|
||||
static_assert((offsetof (struct xm_instrument_header, vibrato_type)) == 235);
|
||||
static_assert((offsetof (struct xm_instrument_header, vibrato_sweep)) == 236);
|
||||
static_assert((offsetof (struct xm_instrument_header, vibrato_depth)) == 237);
|
||||
static_assert((offsetof (struct xm_instrument_header, vibrato_rate)) == 238);
|
||||
static_assert((offsetof (struct xm_instrument_header, volume_fadeout)) == 239);
|
||||
|
||||
typedef struct __attribute__((packed)) xm_sample_header {
|
||||
int32_t sample_length;
|
||||
int32_t sample_loop_start;
|
||||
int32_t sample_loop_length;
|
||||
uint8_t volume;
|
||||
uint8_t finetune;
|
||||
uint8_t type;
|
||||
uint8_t panning;
|
||||
int8_t relative_note_number;
|
||||
uint8_t sample_data_type;
|
||||
int8_t sample_name[22];
|
||||
} xm_sample_header_t;
|
||||
|
||||
static_assert((offsetof (struct xm_sample_header, sample_length)) == 0);
|
||||
static_assert((offsetof (struct xm_sample_header, sample_loop_start)) == 4);
|
||||
static_assert((offsetof (struct xm_sample_header, sample_loop_length)) == 8);
|
||||
static_assert((offsetof (struct xm_sample_header, volume)) == 12);
|
||||
static_assert((offsetof (struct xm_sample_header, finetune)) == 13);
|
||||
static_assert((offsetof (struct xm_sample_header, type)) == 14);
|
||||
static_assert((offsetof (struct xm_sample_header, panning)) == 15);
|
||||
static_assert((offsetof (struct xm_sample_header, relative_note_number)) == 16);
|
||||
static_assert((offsetof (struct xm_sample_header, sample_data_type)) == 17);
|
||||
static_assert((offsetof (struct xm_sample_header, sample_name)) == 18);
|
||||
|
||||
typedef struct __attribute__((packed)) xm_pattern_format {
|
||||
uint8_t note;
|
||||
uint8_t instrument;
|
||||
uint8_t volume_column_byte;
|
||||
uint8_t effect_type;
|
||||
uint8_t effect_parameter;
|
||||
} xm_pattern_format_t;
|
||||
|
||||
static_assert((offsetof (struct xm_pattern_format, note)) == 0);
|
||||
static_assert((offsetof (struct xm_pattern_format, instrument)) == 1);
|
||||
static_assert((offsetof (struct xm_pattern_format, volume_column_byte)) == 2);
|
||||
static_assert((offsetof (struct xm_pattern_format, effect_type)) == 3);
|
||||
static_assert((offsetof (struct xm_pattern_format, effect_parameter)) == 4);
|
Loading…
x
Reference in New Issue
Block a user