1 #include "common.h"
2
3 #ifdef LIBXMP_PAULA_SIMULATOR
4 /*
5 * Based on Antti S. Lankila's reference code, modified for libxmp
6 * by Claudio Matsuoka.
7 */
8 #include "virtual.h"
9 #include "mixer.h"
10 #include "paula.h"
11 #include "precomp_blep.h"
12
libxmp_paula_init(struct context_data * ctx,struct paula_state * paula)13 void libxmp_paula_init(struct context_data *ctx, struct paula_state *paula)
14 {
15 struct mixer_data *s = &ctx->s;
16
17 paula->global_output_level = 0;
18 paula->active_bleps = 0;
19 paula->fdiv = (double)PAULA_HZ / s->freq;
20 paula->remainder = paula->fdiv;
21 }
22
23 /* return output simulated as series of bleps */
output_sample(struct paula_state * paula,int tabnum)24 static int16 output_sample(struct paula_state *paula, int tabnum)
25 {
26 int i;
27 int32 output;
28
29 output = paula->global_output_level << BLEP_SCALE;
30 for (i = 0; i < paula->active_bleps; i++) {
31 int age = paula->blepstate[i].age;
32 int level = paula->blepstate[i].level;
33 output -= winsinc_integral[tabnum][age] * level;
34 }
35 output >>= BLEP_SCALE;
36
37 if (output < -32768)
38 output = -32768;
39 else if (output > 32767)
40 output = 32767;
41
42 return output;
43 }
44
input_sample(struct paula_state * paula,int16 sample)45 static void input_sample(struct paula_state *paula, int16 sample)
46 {
47 if (sample != paula->global_output_level) {
48 /* Start a new blep: level is the difference, age (or phase) is 0 clocks. */
49 if (paula->active_bleps > MAX_BLEPS - 1) {
50 fprintf(stderr, "warning: active blep list truncated!\n");
51 paula->active_bleps = MAX_BLEPS - 1;
52 }
53
54 /* Make room for new blep */
55 memmove(&paula->blepstate[1], &paula->blepstate[0],
56 sizeof(struct blep_state) * paula->active_bleps);
57
58 /* Update state to account for the new blep */
59 paula->active_bleps++;
60 paula->blepstate[0].age = 0;
61 paula->blepstate[0].level = sample - paula->global_output_level;
62 paula->global_output_level = sample;
63 }
64 }
65
do_clock(struct paula_state * paula,int cycles)66 static void do_clock(struct paula_state *paula, int cycles)
67 {
68 int i;
69
70 if (cycles <= 0) {
71 return;
72 }
73
74 for (i = 0; i < paula->active_bleps; i++) {
75 paula->blepstate[i].age += cycles;
76 if (paula->blepstate[i].age >= BLEP_SIZE) {
77 paula->active_bleps = i;
78 break;
79 }
80 }
81 }
82
83 #define LOOP for (; count; count--)
84
85 #define UPDATE_POS(x) do { \
86 frac += (x); \
87 pos += frac >> SMIX_SHIFT; \
88 frac &= SMIX_MASK; \
89 } while (0)
90
91 #define PAULA_SIMULATION(x) do { \
92 int num_in = vi->paula->remainder / MINIMUM_INTERVAL; \
93 int ministep = step / num_in; \
94 int i; \
95 \
96 /* input is always sampled at a higher rate than output */ \
97 for (i = 0; i < num_in - 1; i++) { \
98 input_sample(vi->paula, sptr[pos]); \
99 do_clock(vi->paula, MINIMUM_INTERVAL); \
100 UPDATE_POS(ministep); \
101 } \
102 input_sample(vi->paula, sptr[pos]); \
103 vi->paula->remainder -= num_in * MINIMUM_INTERVAL; \
104 \
105 do_clock(vi->paula, (int)vi->paula->remainder); \
106 smp_in = output_sample(vi->paula, (x)); \
107 do_clock(vi->paula, MINIMUM_INTERVAL - (int)vi->paula->remainder); \
108 UPDATE_POS(step - (num_in - 1) * ministep); \
109 \
110 vi->paula->remainder += vi->paula->fdiv; \
111 } while (0)
112
113 #define MIX_MONO() do { \
114 *(buffer++) += smp_in * vl; \
115 } while (0)
116
117 #define MIX_STEREO() do { \
118 *(buffer++) += smp_in * vr; \
119 *(buffer++) += smp_in * vl; \
120 } while (0)
121
122 #define VAR_NORM(x) \
123 int smp_in; \
124 x *sptr = vi->sptr; \
125 unsigned int pos = vi->pos; \
126 int frac = (1 << SMIX_SHIFT) * (vi->pos - (int)vi->pos)
127
128 #define VAR_PAULA(x) \
129 VAR_NORM(x); \
130 vl <<= 8; \
131 vr <<= 8
132
133
MIXER(mono_a500)134 MIXER(mono_a500)
135 {
136 VAR_PAULA(int8);
137
138 LOOP { PAULA_SIMULATION(0); MIX_MONO(); }
139 }
140
MIXER(mono_a500_filter)141 MIXER(mono_a500_filter)
142 {
143 VAR_PAULA(int8);
144
145 LOOP { PAULA_SIMULATION(1); MIX_MONO(); }
146 }
147
MIXER(stereo_a500)148 MIXER(stereo_a500)
149 {
150 VAR_PAULA(int8);
151
152 LOOP { PAULA_SIMULATION(0); MIX_STEREO(); }
153 }
154
MIXER(stereo_a500_filter)155 MIXER(stereo_a500_filter)
156 {
157 VAR_PAULA(int8);
158
159 LOOP { PAULA_SIMULATION(1); MIX_STEREO(); }
160 }
161
162 #endif /* LIBXMP_PAULA_SIMULATOR */
163