1 
2 /*
3  * The Real SoundTracker - Basic 32bit integers mixer. Probably the
4  * worst which you can come up with.
5  *
6  * Copyright (C) 1998-2019 Michael Krause
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  */
22 
23 #include <config.h>
24 
25 #include <glib/gi18n.h>
26 #include <math.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "mixer.h"
31 #include "tracer.h"
32 
33 static int num_channels, mixfreq, amp = 8;
34 static gint32* mixbuf = NULL;
35 static int mixbufsize = 0, clipflag;
36 static int stereo;
37 
38 typedef struct integer32_channel {
39     st_mixer_sample_info* sample;
40 
41     void* data; /* copy of sample->data */
42     guint32 length; /* length of sample (converted) */
43     guint32 playend; /* for a forced premature end of the sample */
44 
45     int running; /* this channel is active */
46     guint32 current; /* current playback position in sample (converted) */
47     guint32 speed; /* sample playback speed (converted) */
48 
49     guint32 loopstart; /* loop start (converted) */
50     guint32 loopend; /* loop end (converted) */
51     int loopflags; /* 0 none, 1 forward, 2 pingpong */
52     int direction; /* current pingpong direction (+1 forward, -1 backward) */
53 
54     int volume; /* 0..64 */
55     float panning; /* -1.0 .. +1.0 */
56 } integer32_channel;
57 
58 static integer32_channel channels[32];
59 
60 #define ACCURACY 12 /* accuracy of the fixed point stuff, ALSO HARDCODED in the assembly routines!! */
61 
62 #define MAX_SAMPLE_LENGTH ((1 << (32 - ACCURACY)) - 1)
63 
64 static void
integer32_setnumch(int n)65 integer32_setnumch(int n)
66 {
67     g_assert(n >= 1 && n <= 32);
68 
69     num_channels = n;
70 }
71 
72 static void
integer32_updatesample(st_mixer_sample_info * si)73 integer32_updatesample(st_mixer_sample_info* si)
74 {
75     int i;
76     integer32_channel* c;
77 
78     for (i = 0; i < 32; i++) {
79         c = &channels[i];
80         if (c->sample != si || !c->running) {
81             continue;
82         }
83 
84         if (c->data != si->data
85             || c->length != MIN(si->length, MAX_SAMPLE_LENGTH) << ACCURACY
86             || c->loopflags != si->looptype) {
87             c->running = 0;
88         }
89 
90         /* No relevant data has changed. Don't stop the sample, but update
91 	   our local loop data instead. */
92         c->loopstart = MIN(si->loopstart, MAX_SAMPLE_LENGTH) << ACCURACY;
93         c->loopend = MIN(si->loopend, MAX_SAMPLE_LENGTH) << ACCURACY;
94         c->loopflags = si->looptype;
95         if (c->loopflags != ST_MIXER_SAMPLE_LOOPTYPE_NONE) {
96             // we can be more clever here...
97             c->current = c->loopstart;
98             c->direction = 1;
99         }
100     }
101 }
102 
103 static gboolean
integer32_setmixformat(int format)104 integer32_setmixformat(int format)
105 {
106     if (format != 16)
107         return FALSE;
108 
109     return TRUE;
110 }
111 
112 static gboolean
integer32_setstereo(int on)113 integer32_setstereo(int on)
114 {
115     stereo = on;
116     return TRUE;
117 }
118 
119 static void
integer32_setmixfreq(guint32 frequency)120 integer32_setmixfreq(guint32 frequency)
121 {
122     mixfreq = frequency;
123 }
124 
125 static void
integer32_setampfactor(float amplification)126 integer32_setampfactor(float amplification)
127 {
128     amp = 8 * amplification;
129 }
130 
131 static gboolean
integer32_getclipflag(void)132 integer32_getclipflag(void)
133 {
134     return clipflag;
135 }
136 
137 static void
integer32_reset(void)138 integer32_reset(void)
139 {
140     memset(channels, 0, sizeof(channels));
141 }
142 
143 static void
integer32_startnote(int channel,st_mixer_sample_info * s)144 integer32_startnote(int channel,
145     st_mixer_sample_info* s)
146 {
147     integer32_channel* c = &channels[channel];
148 
149     c->sample = s;
150     c->data = s->data;
151     c->length = MIN(s->length, MAX_SAMPLE_LENGTH) << ACCURACY;
152     c->playend = 0;
153     c->running = 1;
154     c->speed = 1;
155     c->current = 0;
156     c->loopstart = MIN(s->loopstart, MAX_SAMPLE_LENGTH) << ACCURACY;
157     c->loopend = MIN(s->loopend, MAX_SAMPLE_LENGTH) << ACCURACY;
158     c->loopflags = s->looptype;
159     c->direction = 1;
160 }
161 
162 static void
integer32_stopnote(int channel)163 integer32_stopnote(int channel)
164 {
165     integer32_channel* c = &channels[channel];
166 
167     c->running = 0;
168 }
169 
170 static void
integer32_setsmplpos(int channel,guint32 offset)171 integer32_setsmplpos(int channel,
172     guint32 offset)
173 {
174     integer32_channel* c = &channels[channel];
175 
176     if (offset<c->length>> ACCURACY) {
177         c->current = offset << ACCURACY;
178         c->direction = 1;
179     } else {
180         c->running = 0;
181     }
182 }
183 
184 static void
integer32_setsmplend(int channel,guint32 offset)185 integer32_setsmplend(int channel,
186     guint32 offset)
187 {
188     integer32_channel* c = &channels[channel];
189 
190     if (c->current != 0 || offset<c->length>> ACCURACY) {
191         c->playend = MIN(offset, MAX_SAMPLE_LENGTH) << ACCURACY;
192     }
193 }
194 
195 static void
integer32_setfreq(int channel,float frequency)196 integer32_setfreq(int channel,
197     float frequency)
198 {
199     integer32_channel* c = &channels[channel];
200 
201     if (frequency > (0x7fffffff >> ACCURACY)) {
202         frequency = (0x7fffffff >> ACCURACY);
203     }
204 
205     c->speed = frequency * (1 << ACCURACY) / mixfreq;
206     if (c->speed == 0) {
207         c->speed = 1;
208     }
209 }
210 
211 static void
integer32_setvolume(int channel,float volume)212 integer32_setvolume(int channel,
213     float volume)
214 {
215     integer32_channel* c = &channels[channel];
216 
217     c->volume = 64 * volume;
218 }
219 
220 static void
integer32_setpanning(int channel,float panning)221 integer32_setpanning(int channel,
222     float panning)
223 {
224     integer32_channel* c = &channels[channel];
225 
226     c->panning = panning;
227 }
228 
229 static void*
integer32_mix(void * dest,guint32 count,gint16 * scopebufs[],int scopebuf_offset)230 integer32_mix(void* dest,
231     guint32 count,
232     gint16* scopebufs[],
233     int scopebuf_offset)
234 {
235     int todo;
236     int i, j, t, *m, v;
237     integer32_channel* c;
238     int done;
239     int offs2end, oflcnt, looplen;
240     gint16* sndbuf;
241     gint16* scopedata = NULL;
242     int vl = 0;
243     int vr = 0;
244     gint16* data;
245     int s, val;
246 
247     if ((stereo + 1) * count > mixbufsize) {
248         g_free(mixbuf);
249         mixbuf = g_new(gint32, (stereo + 1) * count);
250         mixbufsize = (stereo + 1) * count;
251     }
252     memset(mixbuf, 0, (stereo + 1) * 4 * count);
253 
254     for (i = 0; i < num_channels; i++) {
255         c = &channels[i];
256         t = count;
257         m = mixbuf;
258         v = c->volume;
259 
260         if (scopebufs)
261             scopedata = scopebufs[i] + scopebuf_offset;
262 
263         if (!c->running) {
264             if (scopebufs)
265                 memset(scopedata, 0, 2 * count);
266             continue;
267         }
268 
269         g_mutex_lock(&c->sample->lock);
270 
271         while (t) {
272             /* Check how much of the sample we can fill in one run */
273             if (c->loopflags && c->playend == 0) {
274                 looplen = c->loopend - c->loopstart;
275                 g_assert(looplen > 0);
276                 if (c->loopflags == ST_MIXER_SAMPLE_LOOPTYPE_AMIGA) {
277                     offs2end = c->loopend - c->current;
278                     if (offs2end <= 0) {
279                         oflcnt = -offs2end / looplen;
280                         offs2end += oflcnt * looplen;
281                         c->current = c->loopstart - offs2end;
282                         offs2end = c->loopend - c->current;
283                     }
284                 } else /* if(c->loopflags == ST_MIXER_SAMPLE_LOOPTYPE_PINGPONG) */ {
285                     if (c->direction == 1)
286                         offs2end = c->loopend - c->current;
287                     else
288                         offs2end = c->current - c->loopstart;
289 
290                     if (offs2end <= 0) {
291                         oflcnt = -offs2end / looplen;
292                         offs2end += oflcnt * looplen;
293                         if ((oflcnt && 1) ^ (c->direction == -1)) {
294                             c->current = c->loopstart - offs2end;
295                             offs2end = c->loopend - c->current;
296                             c->direction = 1;
297                         } else {
298                             c->current = c->loopend + offs2end;
299                             if (c->current == c->loopend)
300                                 c->current--;
301                             offs2end = c->current - c->loopstart;
302                             c->direction = -1;
303                         }
304                     }
305                 }
306                 g_assert(offs2end >= 0);
307                 done = offs2end / c->speed + 1;
308             } else /* if(c->loopflags == LOOP_NO) */ {
309                 done = ((c->playend ? c->playend : c->length) - c->current) / c->speed;
310                 if (!done) {
311                     c->running = 0;
312                     break;
313                 }
314             }
315 
316             g_assert(done > 0);
317 
318             if (done > t)
319                 done = t;
320             t -= done;
321 
322             g_assert(c->current >= 0 && (c->current >> ACCURACY) < c->length);
323 
324             if (stereo) {
325                 vl = 64 - ((c->panning + 1.0) * 32);
326                 vr = (c->panning + 1.0) * 32;
327             }
328 
329             /* This one does the actual mixing */
330             data = c->data;
331             if (scopebufs) {
332                 if (stereo) {
333                     for (j = c->current, s = c->speed * c->direction; done; done--, j += s) {
334                         val = v * data[j >> ACCURACY];
335                         *m++ += vl * val >> 6;
336                         *m++ += vr * val >> 6;
337                         *scopedata++ = val >> 6;
338                     }
339                 } else {
340                     for (j = c->current, s = c->speed * c->direction; done; done--, j += s) {
341                         val = v * data[j >> ACCURACY];
342                         *m++ += val;
343                         *scopedata++ = val >> 6;
344                     }
345                 }
346             } else {
347                 if (stereo) {
348                     vl *= v;
349                     vr *= v;
350                     for (j = c->current, s = c->speed * c->direction; done; done--, j += s) {
351                         val = data[j >> ACCURACY];
352                         *m++ += vl * val >> 6;
353                         *m++ += vr * val >> 6;
354                     }
355                 } else {
356                     for (j = c->current, s = c->speed * c->direction; done; done--, j += s) {
357                         val = v * data[j >> ACCURACY];
358                         *m++ += val;
359                     }
360                 }
361             }
362 
363             c->current = j;
364         }
365 
366         g_mutex_unlock(&c->sample->lock);
367     }
368 
369     /* modules with many channels get additional amplification here */
370     t = (4 * log(num_channels) / log(4)) * 64 * 8;
371 
372     for (sndbuf = dest, clipflag = 0, todo = 0; todo < (stereo + 1) * count; todo++) {
373         gint32 a, b;
374 
375         a = mixbuf[todo];
376         a *= amp; /* amplify */
377         a /= t;
378 
379         b = CLAMP(a, -32768, 32767);
380         if (a != b) {
381             clipflag = 1;
382         }
383 
384         *sndbuf++ = b;
385     }
386 
387     return dest + (stereo + 1) * 2 * count;
388 }
389 
integer32_dumpstatus(st_mixer_channel_status array[])390 void integer32_dumpstatus(st_mixer_channel_status array[])
391 {
392     int i;
393 
394     for (i = 0; i < 32; i++) {
395         if (channels[i].running) {
396             array[i].current_sample = channels[i].sample;
397             array[i].current_position = channels[i].current >> ACCURACY;
398         } else {
399             array[i].current_sample = NULL;
400         }
401     }
402 }
403 
404 static void
integer32_loadchsettings(int ch)405 integer32_loadchsettings(int ch)
406 {
407     tracer_channel* tch;
408     integer32_channel* c;
409     guint64 tmp64;
410 
411     g_assert(ch < num_channels);
412 
413     tch = tracer_return_channel(ch);
414     c = &channels[ch];
415 
416     c->sample = tch->sample;
417     c->data = tch->data;
418 
419     if (tch->sample) {
420         c->loopflags = tch->sample->looptype;
421         c->loopstart = MIN(tch->sample->loopstart, MAX_SAMPLE_LENGTH) << ACCURACY;
422         c->loopend = MIN(tch->sample->loopend, MAX_SAMPLE_LENGTH) << ACCURACY;
423     }
424     c->length = MIN(tch->length, MAX_SAMPLE_LENGTH) << ACCURACY;
425     c->volume = tch->volume * 64;
426     c->panning = tch->panning;
427     c->direction = tch->direction;
428     c->playend = MIN(tch->playend, MAX_SAMPLE_LENGTH) << ACCURACY;
429     tmp64 = (((guint64)tch->positionw << 32) + tch->positionf) >> (32 - ACCURACY);
430     c->current = MIN(tmp64, MAX_SAMPLE_LENGTH << ACCURACY);
431     tmp64 = (((guint64)tch->freqw << 32) + tch->freqf) >> (32 - ACCURACY);
432     c->speed = MIN(tmp64, MAX_SAMPLE_LENGTH << ACCURACY);
433 
434     c->running = tch->flags & TR_FLAG_SAMPLE_RUNNING;
435 }
436 
437 st_mixer mixer_integer32 = {
438     "integer32",
439     N_("Integers mixer, no interpolation, no filters, maximum sample length 1M"),
440 
441     integer32_setnumch,
442     integer32_updatesample,
443     integer32_setmixformat,
444     integer32_setstereo,
445     integer32_setmixfreq,
446     integer32_setampfactor,
447     integer32_getclipflag,
448     integer32_reset,
449     integer32_startnote,
450     integer32_stopnote,
451     integer32_setsmplpos,
452     integer32_setsmplend,
453     integer32_setfreq,
454     integer32_setvolume,
455     integer32_setpanning,
456     NULL,
457     NULL,
458     integer32_mix,
459     integer32_dumpstatus,
460     integer32_loadchsettings,
461 
462     MAX_SAMPLE_LENGTH,
463 
464     NULL
465 };
466