Fix PCM playback in ZSM backend

This commit is contained in:
Zachary Hall 2024-10-16 13:06:40 -07:00
parent 28314c4372
commit b52a316511
4 changed files with 71 additions and 38 deletions

View file

@ -180,14 +180,21 @@ pcm_render(int16_t *buf, unsigned num_samples)
*(buf++) = (int16_t)((int32_t)cur_r * volume_lut[ctrl & 0xF] / 64);
}
}
uint32_t pcm_fifo_avail(void) {
uint32_t cnt_adj = fifo_cnt;
uint32_t pcm_fifo_cnt(void) {
return fifo_cnt;
}
uint32_t pcm_sample_size(void) {
uint32_t output = 1;
switch ((ctrl >> 4) & 3) {
case 3: cnt_adj /= 2;
case 3: output *= 2;
case 2:
case 1: cnt_adj /= 2;
case 1: output *= 2;
case 0: break;
}
return output;
}
uint32_t pcm_fifo_avail(void) {
uint32_t cnt_adj = fifo_cnt / pcm_sample_size();
uint32_t output = 0;
uint32_t _phase = phase;
while (cnt_adj != 0) {

View file

@ -16,3 +16,5 @@ void pcm_write_fifo(uint8_t val);
void pcm_render(int16_t *buf, unsigned num_samples);
uint32_t pcm_fifo_avail(void);
bool pcm_is_fifo_almost_empty(void);
uint32_t pcm_fifo_cnt(void);
uint32_t pcm_sample_size(void);

View file

@ -47,6 +47,37 @@ void ZsmBackend::load(const char *filename) {
file->read(loop_point, 1, 1);
pcm_offset++;
pcm_data_offs = ((((uint16_t)loop_point[0]) + 1) * 16) + pcm_offset;
for (uint8_t i = 0; i <= loop_point[0]; i++) {
uint16_t instdef = (i * 16) + 1;
pcm_instrument *inst = new pcm_instrument();
file->seek(pcm_offset + instdef, SeekType::SET);
file->read(&inst->geom, 1, 1);
uint8_t bytes[10];
file->read(bytes, 10, 1);
inst->loop_rem = bytes[9];
inst->loop_rem <<= 8;
inst->loop_rem |= bytes[8];
inst->loop_rem <<= 8;
inst->loop_rem |= bytes[7];
inst->loop = loop_rem;
inst->islooped = bytes[6] & 0x80;
inst->remain = bytes[5];
inst->remain <<= 8;
inst->remain |= bytes[4];
inst->remain <<= 8;
inst->remain |= bytes[3];
uint32_t cur = bytes[2];
cur <<= 8;
cur |= bytes[1];
cur <<= 8;
cur |= bytes[0];
cur += pcm_data_offs;
inst->data = (uint8_t*)malloc(inst->remain);
file->seek(cur, SeekType::SET);
file->read(inst->data, 1, inst->remain);
inst->loop_rem = inst->remain - inst->loop_rem;
instruments.push_back(inst);
}
file->seek(music_data_start, SeekType::SET);
this->loop_point = std::max(this->loop_point, (uint32_t)music_data_start);
double prev_time = 0.0;
@ -106,6 +137,11 @@ void ZsmBackend::cleanup() {
audio_buf.clear();
SDL_FreeAudioStream(fm_stream);
fm_stream = nullptr;
audio_sample = nullptr;
for (auto inst : instruments) {
delete inst;
}
instruments.clear();
}
void ZsmBackend::tick(bool step) {
delayTicks -= 1;
@ -167,40 +203,18 @@ void ZsmBackend::tick(bool step) {
uint8_t ctrl = pcm_read_ctrl();
pcm_write_ctrl(ctrl | 0x80);
uint16_t pcm_idx = cmd.extcmd.pcm[i + 1];
uint16_t instdef = pcm_idx * 16;
file->seek(pcm_offset + instdef, SeekType::SET);
uint8_t geom;
file->read(&geom, 1, 1);
pcm_instrument *inst = instruments[pcm_idx];
ctrl = pcm_read_ctrl() & 0x0F;
ctrl |= geom & 0x30;
ctrl |= inst->geom & 0x30;
pcm_write_ctrl(ctrl);
uint8_t bytes[10];
file->read(bytes, 10, 1);
loop_rem = bytes[9];
loop_rem <<= 8;
loop_rem |= bytes[8];
loop_rem <<= 8;
loop_rem |= bytes[7];
loop = loop_rem;
islooped = bytes[6] & 0x80;
remain = bytes[5];
remain <<= 8;
remain |= bytes[4];
remain <<= 8;
remain |= bytes[3];
cur = bytes[2];
cur <<= 8;
cur |= bytes[1];
cur <<= 8;
cur |= bytes[0];
cur += pcm_data_offs;
loop += cur;
loop_rem = remain - loop_rem;
file->seek(file_pos, SeekType::SET);
audio_sample = inst->data;
loop = inst->loop;
loop_rem = inst->loop_rem;
remain = inst->remain;
islooped = inst->islooped;
cur = 0;
} break;
}
//cmd.extcmd.pcm
audio_step(0);
} break;
}
// Nothing handled yet.

View file

@ -60,6 +60,17 @@ struct ZsmCommand {
};
~ZsmCommand();
};
struct pcm_instrument {
uint8_t geom;
uint32_t loop_rem;
uint32_t loop;
bool islooped;
uint32_t remain;
uint8_t *data = nullptr;
inline ~pcm_instrument() {
if (data != nullptr) free((void*)data);
}
};
class ZsmBackend : public PlaybackBackend {
File *file;
Fifo<int16_t> audio_buf;
@ -80,6 +91,8 @@ class ZsmBackend : public PlaybackBackend {
uint32_t pcm_loop_point;
uint32_t rem_point;
SDL_AudioStream *fm_stream;
std::vector<pcm_instrument*> instruments;
uint8_t *audio_sample = nullptr;
int16_t combine_audio(int16_t a, int16_t b) {
return (int16_t)((((int32_t)a) + ((int32_t)b)) >> 1);
}
@ -96,11 +109,8 @@ class ZsmBackend : public PlaybackBackend {
}
}
size_t oldpos = file->get_pos();
file->seek((cur++), SeekType::SET);
uint8_t sample;
file->read(&sample, 1, 1);
uint8_t sample = audio_sample[cur++];
pcm_write_fifo(sample);
file->seek(oldpos, SeekType::SET);
}
samples *= 2;
int16_t *psg_ptr = psg_buf.get_item_sized<int16_t>(samples);