28 static void allocateMixBuffer(
unsigned size)
35 mixBuffer =
reinterpret_cast<int*
>((tmp + 15) & ~15);
39 static string makeUnique(MSXMixer& mixer,
string_ref name)
41 string result = name.
str();
42 if (mixer.findDevice(result)) {
46 }
while (mixer.findDevice(result));
53 unsigned numChannels_,
bool stereo_)
55 , name(makeUnique(mixer, name_))
56 , description(description_.str())
57 , numChannels(numChannels_)
58 , stereo(stereo_ ? 2 : 1)
59 , numRecordChannels(0)
63 assert(stereo == 1 || stereo == 2);
66 for (
unsigned i = 0; i < numChannels; ++i) {
67 channelMuted[i] =
false;
68 channelBalance[i] = 0;
88 return stereo == 2 || !balanceCenter;
102 if (mode ==
"mono") {
104 }
else if (mode ==
"left") {
106 }
else if (mode ==
"right") {
112 for (
auto& b : soundConfig.
getChildren(
"balance")) {
113 int balance = b->getDataAsInt();
115 if (!b->hasAttribute(
"channel")) {
116 devBalance = balance;
121 if (balance != 0 && balance != -100 && balance != 100) {
123 "balance " << balance <<
" illegal");
126 balanceCenter =
false;
129 const string& range = b->getAttribute(
"channel");
131 channelBalance[c - 1] = balance;
135 mixer.registerSound(*
this, volume, devBalance, numChannels);
140 mixer.unregisterSound(*
this);
145 mixer.updateStream(time);
150 inputSampleRate = sampleRate;
155 assert(channel < numChannels);
156 bool wasRecording = writer[channel].get() !=
nullptr;
157 if (!filename.
empty()) {
158 writer[channel] = make_unique<Wav16Writer>(
159 filename, stereo, inputSampleRate);
161 writer[channel].reset();
163 bool recording = writer[channel].get() !=
nullptr;
164 if (recording != wasRecording) {
166 if (numRecordChannels == 0) {
167 mixer.setSynchronousMode(
true);
170 assert(numRecordChannels <= numChannels);
172 assert(numRecordChannels > 0);
174 if (numRecordChannels == 0) {
175 mixer.setSynchronousMode(
false);
183 assert(channel < numChannels);
184 channelMuted[channel] = muted;
190 assert((
long(dataOut) & 15) == 0);
192 if (samples == 0)
return true;
193 unsigned outputStereo =
isStereo() ? 2 : 1;
196 mset(reinterpret_cast<unsigned*>(dataOut), outputStereo * samples, 0);
198 VLA(
int*, bufs, numChannels);
199 unsigned separateChannels = 0;
200 unsigned pitch = (samples * stereo + 3) & ~3;
204 for (
unsigned i = 0; i < numChannels; ++i) {
205 if (!channelMuted[i] && !writer[i].
get() && balanceCenter) {
214 if (separateChannels) {
215 allocateMixBuffer(pitch * separateChannels);
216 mset(reinterpret_cast<unsigned*>(
mixBuffer),
217 pitch * separateChannels, 0);
220 for (
unsigned i = 0; i < numChannels; ++i) {
221 if (!(!channelMuted[i] && !writer[i].
get() && balanceCenter)) {
225 assert(count == separateChannels);
233 if (separateChannels == 0) {
234 for (
unsigned i = 0; i < numChannels; ++i) {
243 for (
unsigned i = 0; i < numChannels; ++i) {
244 if (writer[i].
get()) {
245 assert(bufs[i] != dataOut);
250 writer[i]->writeSilence(stereo, samples);
256 bool anyUnmuted =
false;
258 VLA(
int, mixBalance, numChannels);
259 for (
unsigned i = 0; i < numChannels; ++i) {
260 if (bufs[i] && !channelMuted[i]) {
262 if (bufs[i] != dataOut) {
263 bufs[numMix] = bufs[i];
264 mixBalance[numMix] = channelBalance[i];
276 if (!balanceCenter) {
285 if (mixBalance[j] <= 0) {
286 left0 += bufs[j][i + 0];
287 left1 += bufs[j][i + 1];
289 if (mixBalance[j] >= 0) {
290 right0 += bufs[j][i + 0];
291 right1 += bufs[j][i + 1];
294 }
while (j < numMix);
295 dataOut[i * 2 + 0] = left0;
296 dataOut[i * 2 + 1] = right0;
297 dataOut[i * 2 + 2] = left1;
298 dataOut[i * 2 + 3] = right1;
300 }
while (i < samples);
309 unsigned num = samples * stereo;
312 int out0 = dataOut[i + 0];
313 int out1 = dataOut[i + 1];
314 int out2 = dataOut[i + 2];
315 int out3 = dataOut[i + 3];
318 out0 += bufs[j][i + 0];
319 out1 += bufs[j][i + 1];
320 out2 += bufs[j][i + 2];
321 out3 += bufs[j][i + 3];
323 }
while (j < numMix);
324 dataOut[i + 0] = out0;
325 dataOut[i + 1] = out1;
326 dataOut[i + 2] = out2;
327 dataOut[i + 3] = out3;
336 return mixer.getHostSampleClock();
340 return mixer.getEffectiveSpeed();