summaryrefslogtreecommitdiff
path: root/src/player/mixutil.c
blob: 451883219272fd879f92cbca1e6e7d33e0271670 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/*
 * Schism Tracker - a cross-platform Impulse Tracker clone
 * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com>
 * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org>
 * copyright (c) 2009 Storlek & Mrs. Brisby
 * copyright (c) 2010-2012 Storlek
 * URL: http://schismtracker.org/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <string.h>

#include "sndfile.h"

#include "cmixer.h"

#define OFSDECAYSHIFT 8
#define OFSDECAYMASK  0xFF


void init_mix_buffer(int *buffer, unsigned int samples)
{
    memset(buffer, 0, samples * sizeof(int));
}


void stereo_fill(int *buffer, unsigned int samples, int* profs, int *plofs)
{
    int rofs = *profs;
    int lofs = *plofs;

    if (!rofs && !lofs) {
	init_mix_buffer(buffer, samples * 2);
	return;
    }

    for (unsigned int i = 0; i < samples; i++) {
	int x_r = (rofs + (((-rofs) >> 31) & OFSDECAYMASK)) >> OFSDECAYSHIFT;
	int x_l = (lofs + (((-lofs) >> 31) & OFSDECAYMASK)) >> OFSDECAYSHIFT;

	rofs -= x_r;
	lofs -= x_l;
	buffer[i * 2 ]    = x_r;
	buffer[i * 2 + 1] = x_l;
    }

    *profs = rofs;
    *plofs = lofs;
}


void end_channel_ofs(song_voice_t *channel, int *buffer, unsigned int samples)
{
    int rofs = channel->rofs;
    int lofs = channel->lofs;

    if (!rofs && !lofs)
	return;

    for (unsigned int i = 0; i < samples; i++) {
	int x_r = (rofs + (((-rofs) >> 31) & OFSDECAYMASK)) >> OFSDECAYSHIFT;
	int x_l = (lofs + (((-lofs) >> 31) & OFSDECAYMASK)) >> OFSDECAYSHIFT;

	rofs -= x_r;
	lofs -= x_l;
	buffer[i * 2]     += x_r;
	buffer[i * 2 + 1] += x_l;
    }

    channel->rofs = rofs;
    channel->lofs = lofs;
}


void mono_from_stereo(int *mix_buf, unsigned int samples)
{
    for (unsigned int j, i = 0; i < samples; i++) {
	j = i << 1;
	mix_buf[i] = (mix_buf[j] + mix_buf[j + 1]) >> 1;
    }
}


static const float f2ic = (float) (1 << 28);
static const float i2fc = (float) (1.0 / (1 << 28));


void stereo_mix_to_float(const int *src, float *out1, float *out2, unsigned int count)
{
    for (unsigned int i = 0; i < count; i++) {
	*out1++ = *src * i2fc;
	src++;

	*out2++ = *src * i2fc;
	src++;
    }
}


void float_to_stereo_mix(const float *in1, const float *in2, int *out, unsigned int count)
{
    for (unsigned int i = 0; i < count; i++) {
	*out++ = (int) (*in1 * f2ic);
	*out++ = (int) (*in2 * f2ic);
	in1++;
	in2++;
    }
}


void mono_mix_to_float(const int *src, float *out, unsigned int count)
{
    for (unsigned int i = 0; i < count; i++) {
	*out++ = *src * i2fc;
	src++;
    }
}


void float_to_mono_mix(const float *in, int *out, unsigned int count)
{
    for (unsigned int i = 0; i < count; i++) {
	*out++ = (int) (*in * f2ic);
	in++;
    }
}


// ----------------------------------------------------------------------------
// Clip and convert functions
// ----------------------------------------------------------------------------
// XXX mins/max were int[2]
//
// The original C version was written by Rani Assaf <rani@magic.metawire.com>


// Clip and convert to 8 bit. mins and maxs returned in 27bits: [MIXING_CLIPMIN..MIXING_CLIPMAX]. mins[0] left, mins[1] right.
unsigned int clip_32_to_8(void *ptr, int *buffer, unsigned int samples, int *mins, int *maxs)
{
    unsigned char *p = (unsigned char *) ptr;

    for (unsigned int i = 0; i < samples; i++) {
	int n = buffer[i];

	if (n < MIXING_CLIPMIN)
	    n = MIXING_CLIPMIN;
	else if (n > MIXING_CLIPMAX)
	    n = MIXING_CLIPMAX;

	if (n < mins[i & 1])
	    mins[i & 1] = n;
	else if (n > maxs[i & 1])
	    maxs[i & 1] = n;

	// 8-bit unsigned
	p[i] = (n >> (24 - MIXING_ATTENUATION)) ^ 0x80;
    }

    return samples;
}


// Clip and convert to 16 bit. mins and maxs returned in 27bits: [MIXING_CLIPMIN..MIXING_CLIPMAX]. mins[0] left, mins[1] right.
unsigned int clip_32_to_16(void *ptr, int *buffer, unsigned int samples, int *mins, int *maxs)
{
    signed short *p = (signed short *) ptr;

    for (unsigned int i = 0; i < samples; i++) {
	int n = buffer[i];

	if (n < MIXING_CLIPMIN)
	    n = MIXING_CLIPMIN;
	else if (n > MIXING_CLIPMAX)
	    n = MIXING_CLIPMAX;

	if (n < mins[i & 1])
	    mins[i & 1] = n;
	else if (n > maxs[i & 1])
	    maxs[i & 1] = n;

	// 16-bit signed
	p[i] = n >> (16 - MIXING_ATTENUATION);
    }

    return samples * 2;
}


// Clip and convert to 24 bit. mins and maxs returned in 27bits: [MIXING_CLIPMIN..MIXING_CLIPMAX]. mins[0] left, mins[1] right.
// Note, this is 24bit, not 24-in-32bits. The former is used in .wav. The latter is used in audio IO
unsigned int clip_32_to_24(void *ptr, int *buffer, unsigned int samples, int *mins, int *maxs)
{
    /* the inventor of 24bit anything should be shot */
    unsigned char *p = (unsigned char *) ptr;

    for (unsigned int i = 0; i < samples; i++) {
	int n = buffer[i];

	if (n < MIXING_CLIPMIN)
	    n = MIXING_CLIPMIN;
	else if (n > MIXING_CLIPMAX)
	    n = MIXING_CLIPMAX;

	if (n < mins[i & 1])
	    mins[i & 1] = n;
	else if (n > maxs[i & 1])
	    maxs[i & 1] = n;

	// 24-bit signed
	n = n >> (8 - MIXING_ATTENUATION);

	/* err, assume same endian */
	memcpy(p, &n, 3);
	p += 3;
    }

    return samples * 3;
}


// Clip and convert to 32 bit(int). mins and maxs returned in 27bits: [MIXING_CLIPMIN..MIXING_CLIPMAX]. mins[0] left, mins[1] right.
unsigned int clip_32_to_32(void *ptr, int *buffer, unsigned int samples, int *mins, int *maxs)
{
    signed int *p = (signed int *) ptr;

    for (unsigned int i = 0; i < samples; i++) {
	int n = buffer[i];

	if (n < MIXING_CLIPMIN)
	    n = MIXING_CLIPMIN;
	else if (n > MIXING_CLIPMAX)
	    n = MIXING_CLIPMAX;

	if (n < mins[i & 1])
	    mins[i & 1] = n;
	else if (n > maxs[i & 1])
	    maxs[i & 1] = n;

	// 32-bit signed
	p[i] = (n << MIXING_ATTENUATION);
    }

    return samples * 4;
}
© All Rights Reserved