aboutsummaryrefslogtreecommitdiff
path: root/libopna/opnatimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'libopna/opnatimer.c')
-rw-r--r--libopna/opnatimer.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/libopna/opnatimer.c b/libopna/opnatimer.c
new file mode 100644
index 0000000..195e426
--- /dev/null
+++ b/libopna/opnatimer.c
@@ -0,0 +1,79 @@
+#include "opnatimer.h"
+#include "opna.h"
+
+enum {
+ TIMERB_SHIFT = 4,
+ TIMERB_BITS = 8 + TIMERB_SHIFT,
+};
+
+void opna_timer_reset(struct opna_timer *timer, struct opna *opna) {
+ timer->opna = opna;
+ timer->status = 0;
+ timer->interrupt_cb = 0;
+ timer->interrupt_userptr = 0;
+ timer->mix_cb = 0;
+ timer->mix_userptr = 0;
+ timer->timerb = 0;
+ timer->timerb_load = false;
+ timer->timerb_enable = false;
+ timer->timerb_cnt = 0;
+}
+
+uint8_t opna_timer_status(const struct opna_timer *timer) {
+ return timer->status;
+}
+
+void opna_timer_set_int_callback(struct opna_timer *timer, opna_timer_int_cb_t func, void *userptr) {
+ timer->interrupt_cb = func;
+ timer->interrupt_userptr = userptr;
+}
+
+void opna_timer_set_mix_callback(struct opna_timer *timer, opna_timer_mix_cb_t func, void *userptr) {
+ timer->mix_cb = func;
+ timer->mix_userptr = userptr;
+}
+
+void opna_timer_writereg(struct opna_timer *timer, unsigned reg, unsigned val) {
+ val &= 0xff;
+ opna_writereg(timer->opna, reg, val);
+ switch (reg) {
+ case 0x26:
+ timer->timerb = val;
+ timer->timerb_cnt = timer->timerb << TIMERB_SHIFT;
+ break;
+ case 0x27:
+ timer->timerb_load = val & (1<<1);
+ timer->timerb_enable = val & (1<<3);
+ if (val & (1<<5)) {
+ //timer->timerb_cnt = timer->timerb << TIMERB_SHIFT;
+ timer->status &= ~(1<<1);
+ }
+ }
+}
+
+void opna_timer_mix(struct opna_timer *timer, int16_t *buf, unsigned samples) {
+ do {
+ unsigned generate_samples = samples;
+ if (timer->timerb_enable) {
+ unsigned timerb_samples = (1<<TIMERB_BITS) - timer->timerb_cnt;
+ if (timerb_samples < generate_samples) {
+ generate_samples = timerb_samples;
+ }
+ }
+ opna_mix(timer->opna, buf, generate_samples);
+ if (timer->mix_cb) {
+ timer->mix_cb(timer->mix_userptr, buf, generate_samples);
+ }
+ buf += generate_samples*2;
+ samples -= generate_samples;
+ if (timer->timerb_load) {
+ timer->timerb_cnt = (timer->timerb_cnt + generate_samples) & ((1<<TIMERB_BITS)-1);
+ if (!timer->timerb_cnt && timer->timerb_enable) {
+ if (!(timer->status & (1<<1))) {
+ timer->status |= (1<<1);
+ timer->interrupt_cb(timer->interrupt_userptr);
+ }
+ }
+ }
+ } while (samples);
+}