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