Fix PCM playback in ZSM backend
This commit is contained in:
parent
28314c4372
commit
b52a316511
4 changed files with 71 additions and 38 deletions
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue