looper/backends/playback/zsm/zsm_backend.hpp

148 lines
3.6 KiB
C++

#pragma once
#include "playback_backend.hpp"
#include <omp.h>
#include "x16emu/ymglue.h"
#include <cstdint>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <streambuf>
#include <vector>
#include <util.hpp>
#include <SDL.h>
extern "C" {
#include "x16emu/audio.h"
#include "x16emu/vera_pcm.h"
#include "x16emu/vera_psg.h"
#include "x16emu/ymglue.h"
}
#include "file_backend.hpp"
#define YM_FREQ (3579545/64)
#define PSG_FREQ (AUDIO_SAMPLERATE)
enum ZsmCommandId {
PsgWrite,
ExtCmd,
FmWrite,
ZsmEOF,
Delay
};
struct reg_pair {
uint8_t reg;
uint8_t val;
};
struct ZsmCommand {
ZsmCommandId id;
union {
struct {
uint8_t reg;
uint8_t val;
} psg_write;
struct {
uint8_t channel;
uint8_t bytes;
union {
uint8_t *pcm;
struct {
uint8_t chip_id;
uint8_t writes;
uint8_t *write_bytes;
} expansion;
uint8_t *sync;
uint8_t *custom;
};
} extcmd;
struct {
uint8_t len;
reg_pair *regs;
} fm_write;
uint8_t delay;
};
~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;
DynPtr psg_buf;
DynPtr pcm_buf;
DynPtr out_buf;
DynPtr ym_buf;
DynPtr ym_resample_buf;
bool ym_recorded = false;
uint8_t ym_data[256];
uint32_t loop_rem;
uint32_t pcm_data_offs;
uint8_t pcm_data_instruments;
uint32_t loop;
bool islooped;
uint32_t remain;
uint32_t cur;
uint32_t pcm_loop_point;
uint32_t rem_point;
SDL_AudioStream *fm_stream;
std::vector<pcm_instrument*> instruments;
uint8_t *audio_sample = nullptr;
bool pcm_enable();
bool psg_enable();
bool fm_enable();
double pcm_volume();
double psg_volume();
double fm_volume();
void audio_step(size_t samples);
inline void *reserve(size_t len) {
return (void*)audio_buf.reserve(len);
}
inline size_t copy_out(void *buf, size_t len) {
return audio_buf.pop((int16_t*)buf, len);
}
uint32_t loop_point;
double loop_pos = 0.0;
uint32_t pcm_offset;
uint8_t fm_mask;
uint16_t psg_channel_mask;
uint16_t tick_rate;
size_t music_data_start;
size_t music_data_len;
double ticks;
ssize_t delayTicks = 0;
double position;
double cpuClocks = 0;
inline double get_delay_per_frame() {
return 1.0;
}
void tick(bool step = true);\
void seek_internal(double position, bool loop = true);
ZsmCommand get_command();
public:
uint64_t get_min_samples() override;
std::optional<uint64_t> get_max_samples() override;
inline std::string get_id() override {
return "zsm";
}
inline std::string get_name() override {
return "ZSM player";
}
std::vector<Property> get_property_list() override;
void seek(double position) override;
void load(const char *filename) override;
void switch_stream(int idx) override;
void cleanup() override;
int get_stream_idx() override;
size_t render(void *buf, size_t maxlen) override;
double get_position() override;
inline double get_length() override {
return length;
}
inline ~ZsmBackend() override { }
};