diff --git a/backends/playback/zsm/x16emu/vera_pcm.c b/backends/playback/zsm/x16emu/vera_pcm.c index 1e617c7..1aecf04 100644 --- a/backends/playback/zsm/x16emu/vera_pcm.c +++ b/backends/playback/zsm/x16emu/vera_pcm.c @@ -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) { diff --git a/backends/playback/zsm/x16emu/vera_pcm.h b/backends/playback/zsm/x16emu/vera_pcm.h index 79c3b30..17247cd 100644 --- a/backends/playback/zsm/x16emu/vera_pcm.h +++ b/backends/playback/zsm/x16emu/vera_pcm.h @@ -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); diff --git a/backends/playback/zsm/zsm_backend.cpp b/backends/playback/zsm/zsm_backend.cpp index ae40b82..dcc4ad5 100644 --- a/backends/playback/zsm/zsm_backend.cpp +++ b/backends/playback/zsm/zsm_backend.cpp @@ -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. diff --git a/backends/playback/zsm/zsm_backend.hpp b/backends/playback/zsm/zsm_backend.hpp index c5e6037..febcf23 100644 --- a/backends/playback/zsm/zsm_backend.hpp +++ b/backends/playback/zsm/zsm_backend.hpp @@ -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 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 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(samples);