Bug Summary

File:Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp
Location:line 528, column 29
Description:Array access results in a null pointer dereference

Annotated Source Code

1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "StringUtil.h"
6
7#include "../MailHandler.h"
8#include "Mixer.h"
9
10#include "UCodes.h"
11#include "UCode_AXStructs.h"
12#include "UCode_AXWii.h"
13
14#define AX_WII
15#include "UCode_AX_Voice.h"
16
17
18CUCode_AXWii::CUCode_AXWii(DSPHLE *dsp_hle, u32 l_CRC)
19 : CUCode_AX(dsp_hle, l_CRC),
20 m_last_main_volume(0x8000)
21{
22 for (int i = 0; i < 3; ++i)
23 m_last_aux_volumes[i] = 0x8000;
24 WARN_LOG(DSPHLE, "Instantiating CUCode_AXWii")do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::DSPHLE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp"
, 24, "Instantiating CUCode_AXWii"); } } while (0)
;
25
26 m_old_axwii = (l_CRC == 0xfa450138);
27}
28
29CUCode_AXWii::~CUCode_AXWii()
30{
31}
32
33void CUCode_AXWii::HandleCommandList()
34{
35 // Temp variables for addresses computation
36 u16 addr_hi, addr_lo;
37 u16 addr2_hi, addr2_lo;
38 u16 volume;
39
40 u32 pb_addr = 0;
41
42// WARN_LOG(DSPHLE, "Command list:");
43// for (u32 i = 0; m_cmdlist[i] != CMD_END; ++i)
44// WARN_LOG(DSPHLE, "%04x", m_cmdlist[i]);
45// WARN_LOG(DSPHLE, "-------------");
46
47 u32 curr_idx = 0;
48 bool end = false;
49 while (!end)
50 {
51 u16 cmd = m_cmdlist[curr_idx++];
52
53 if (m_old_axwii)
54 {
55 switch (cmd)
56 {
57 // Some of these commands are unknown, or unused in this AX HLE.
58 // We still need to skip their arguments using "curr_idx += N".
59
60 case CMD_SETUP_OLD:
61 addr_hi = m_cmdlist[curr_idx++];
62 addr_lo = m_cmdlist[curr_idx++];
63 SetupProcessing(HILO_TO_32(addr)((addr_hi << 16) | addr_lo));
64 break;
65
66 case CMD_ADD_TO_LR_OLD:
67 case CMD_SUB_TO_LR_OLD:
68 addr_hi = m_cmdlist[curr_idx++];
69 addr_lo = m_cmdlist[curr_idx++];
70 AddToLR(HILO_TO_32(addr)((addr_hi << 16) | addr_lo), cmd == CMD_SUB_TO_LR_OLD);
71 break;
72
73 case CMD_ADD_SUB_TO_LR_OLD:
74 addr_hi = m_cmdlist[curr_idx++];
75 addr_lo = m_cmdlist[curr_idx++];
76 AddSubToLR(HILO_TO_32(addr)((addr_hi << 16) | addr_lo));
77 break;
78
79 case CMD_PB_ADDR_OLD:
80 addr_hi = m_cmdlist[curr_idx++];
81 addr_lo = m_cmdlist[curr_idx++];
82 pb_addr = HILO_TO_32(addr)((addr_hi << 16) | addr_lo);
83 break;
84
85 case CMD_PROCESS_OLD:
86 ProcessPBList(pb_addr);
87 break;
88
89 case CMD_MIX_AUXA_OLD:
90 case CMD_MIX_AUXB_OLD:
91 case CMD_MIX_AUXC_OLD:
92 volume = m_cmdlist[curr_idx++];
93 addr_hi = m_cmdlist[curr_idx++];
94 addr_lo = m_cmdlist[curr_idx++];
95 addr2_hi = m_cmdlist[curr_idx++];
96 addr2_lo = m_cmdlist[curr_idx++];
97 MixAUXSamples(cmd - CMD_MIX_AUXA_OLD, HILO_TO_32(addr)((addr_hi << 16) | addr_lo), HILO_TO_32(addr2)((addr2_hi << 16) | addr2_lo), volume);
98 break;
99
100 case CMD_UPL_AUXA_MIX_LRSC_OLD:
101 case CMD_UPL_AUXB_MIX_LRSC_OLD:
102 {
103 volume = m_cmdlist[curr_idx++];
104 u32 addresses[6] = {
105 (u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1],
106 (u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3],
107 (u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5],
108 (u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7],
109 (u32)(m_cmdlist[curr_idx + 8] << 16) | m_cmdlist[curr_idx + 9],
110 (u32)(m_cmdlist[curr_idx + 10] << 16) | m_cmdlist[curr_idx + 11],
111 };
112 curr_idx += 12;
113 UploadAUXMixLRSC(cmd == CMD_UPL_AUXB_MIX_LRSC_OLD, addresses, volume);
114 break;
115 }
116
117 // TODO(delroth): figure this one out, it's used by almost every
118 // game I've tested so far.
119 case CMD_UNK_0B_OLD: curr_idx += 4; break;
120
121 case CMD_OUTPUT_OLD:
122 case CMD_OUTPUT_DPL2_OLD:
123 addr_hi = m_cmdlist[curr_idx++];
124 addr_lo = m_cmdlist[curr_idx++];
125 addr2_hi = m_cmdlist[curr_idx++];
126 addr2_lo = m_cmdlist[curr_idx++];
127 OutputSamples(HILO_TO_32(addr2)((addr2_hi << 16) | addr2_lo), HILO_TO_32(addr)((addr_hi << 16) | addr_lo), 0x8000,
128 cmd == CMD_OUTPUT_DPL2_OLD);
129 break;
130
131 case CMD_WM_OUTPUT_OLD:
132 {
133 u32 addresses[4] = {
134 (u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1],
135 (u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3],
136 (u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5],
137 (u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7],
138 };
139 curr_idx += 8;
140 OutputWMSamples(addresses);
141 break;
142 }
143
144 case CMD_END_OLD:
145 end = true;
146 break;
147 }
148 }
149 else
150 {
151 switch (cmd)
152 {
153 // Some of these commands are unknown, or unused in this AX HLE.
154 // We still need to skip their arguments using "curr_idx += N".
155
156 case CMD_SETUP:
157 addr_hi = m_cmdlist[curr_idx++];
158 addr_lo = m_cmdlist[curr_idx++];
159 SetupProcessing(HILO_TO_32(addr)((addr_hi << 16) | addr_lo));
160 break;
161
162 case CMD_ADD_TO_LR:
163 case CMD_SUB_TO_LR:
164 addr_hi = m_cmdlist[curr_idx++];
165 addr_lo = m_cmdlist[curr_idx++];
166 AddToLR(HILO_TO_32(addr)((addr_hi << 16) | addr_lo), cmd == CMD_SUB_TO_LR);
167 break;
168
169 case CMD_ADD_SUB_TO_LR:
170 addr_hi = m_cmdlist[curr_idx++];
171 addr_lo = m_cmdlist[curr_idx++];
172 AddSubToLR(HILO_TO_32(addr)((addr_hi << 16) | addr_lo));
173 break;
174
175 case CMD_PROCESS:
176 addr_hi = m_cmdlist[curr_idx++];
177 addr_lo = m_cmdlist[curr_idx++];
178 ProcessPBList(HILO_TO_32(addr)((addr_hi << 16) | addr_lo));
179 break;
180
181 case CMD_MIX_AUXA:
182 case CMD_MIX_AUXB:
183 case CMD_MIX_AUXC:
184 volume = m_cmdlist[curr_idx++];
185 addr_hi = m_cmdlist[curr_idx++];
186 addr_lo = m_cmdlist[curr_idx++];
187 addr2_hi = m_cmdlist[curr_idx++];
188 addr2_lo = m_cmdlist[curr_idx++];
189 MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr)((addr_hi << 16) | addr_lo), HILO_TO_32(addr2)((addr2_hi << 16) | addr2_lo), volume);
190 break;
191
192 case CMD_UPL_AUXA_MIX_LRSC:
193 case CMD_UPL_AUXB_MIX_LRSC:
194 {
195 volume = m_cmdlist[curr_idx++];
196 u32 addresses[6] = {
197 (u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1],
198 (u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3],
199 (u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5],
200 (u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7],
201 (u32)(m_cmdlist[curr_idx + 8] << 16) | m_cmdlist[curr_idx + 9],
202 (u32)(m_cmdlist[curr_idx + 10] << 16) | m_cmdlist[curr_idx + 11],
203 };
204 curr_idx += 12;
205 UploadAUXMixLRSC(cmd == CMD_UPL_AUXB_MIX_LRSC, addresses, volume);
206 break;
207 }
208
209 // TODO(delroth): figure this one out, it's used by almost every
210 // game I've tested so far.
211 case CMD_UNK_0A: curr_idx += 4; break;
212
213 case CMD_OUTPUT:
214 case CMD_OUTPUT_DPL2:
215 volume = m_cmdlist[curr_idx++];
216 addr_hi = m_cmdlist[curr_idx++];
217 addr_lo = m_cmdlist[curr_idx++];
218 addr2_hi = m_cmdlist[curr_idx++];
219 addr2_lo = m_cmdlist[curr_idx++];
220 OutputSamples(HILO_TO_32(addr2)((addr2_hi << 16) | addr2_lo), HILO_TO_32(addr)((addr_hi << 16) | addr_lo), volume,
221 cmd == CMD_OUTPUT_DPL2);
222 break;
223
224 case CMD_WM_OUTPUT:
225 {
226 u32 addresses[4] = {
227 (u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1],
228 (u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3],
229 (u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5],
230 (u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7],
231 };
232 curr_idx += 8;
233 OutputWMSamples(addresses);
234 break;
235 }
236
237 case CMD_END:
238 end = true;
239 break;
240 }
241 }
242 }
243}
244
245void CUCode_AXWii::SetupProcessing(u32 init_addr)
246{
247 // TODO: should be easily factorizable with AX
248 s16 init_data[60];
249
250 for (u32 i = 0; i < 60; ++i)
251 init_data[i] = HLEMemory_Read_U16(init_addr + 2 * i);
252
253 // List of all buffers we have to initialize
254 struct {
255 int* ptr;
256 u32 samples;
257 } buffers[] = {
258 { m_samples_left, 32 },
259 { m_samples_right, 32 },
260 { m_samples_surround, 32 },
261 { m_samples_auxA_left, 32 },
262 { m_samples_auxA_right, 32 },
263 { m_samples_auxA_surround, 32 },
264 { m_samples_auxB_left, 32 },
265 { m_samples_auxB_right, 32 },
266 { m_samples_auxB_surround, 32 },
267 { m_samples_auxC_left, 32 },
268 { m_samples_auxC_right, 32 },
269 { m_samples_auxC_surround, 32 },
270
271 { m_samples_wm0, 6 },
272 { m_samples_aux0, 6 },
273 { m_samples_wm1, 6 },
274 { m_samples_aux1, 6 },
275 { m_samples_wm2, 6 },
276 { m_samples_aux2, 6 },
277 { m_samples_wm3, 6 },
278 { m_samples_aux3, 6 }
279 };
280
281 u32 init_idx = 0;
282 for (u32 i = 0; i < sizeof (buffers) / sizeof (buffers[0]); ++i)
283 {
284 s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]);
285 s16 delta = (s16)init_data[init_idx + 2];
286
287 init_idx += 3;
288
289 if (!init_val)
290 {
291 memset(buffers[i].ptr, 0, 3 * buffers[i].samples * sizeof (int));
292 }
293 else
294 {
295 for (u32 j = 0; j < 3 * buffers[i].samples; ++j)
296 {
297 buffers[i].ptr[j] = init_val;
298 init_val += delta;
299 }
300 }
301 }
302}
303
304void CUCode_AXWii::AddToLR(u32 val_addr, bool neg)
305{
306 int* ptr = (int*)HLEMemory_Get_Pointer(val_addr);
307 for (int i = 0; i < 32 * 3; ++i)
308 {
309 int val = (int)Common::swap32(*ptr++);
310 if (neg)
311 val = -val;
312
313 m_samples_left[i] += val;
314 m_samples_right[i] += val;
315 }
316}
317
318void CUCode_AXWii::AddSubToLR(u32 val_addr)
319{
320 int* ptr = (int*)HLEMemory_Get_Pointer(val_addr);
321 for (int i = 0; i < 32 * 3; ++i)
322 {
323 int val = (int)Common::swap32(*ptr++);
324 m_samples_left[i] += val;
325 }
326 for (int i = 0; i < 32 * 3; ++i)
327 {
328 int val = (int)Common::swap32(*ptr++);
329 m_samples_right[i] -= val;
330 }
331}
332
333AXMixControl CUCode_AXWii::ConvertMixerControl(u32 mixer_control)
334{
335 u32 ret = 0;
336
337 if (mixer_control & 0x00000001) ret |= MIX_L;
338 if (mixer_control & 0x00000002) ret |= MIX_R;
339 if (mixer_control & 0x00000004) ret |= MIX_L_RAMP | MIX_R_RAMP;
340 if (mixer_control & 0x00000008) ret |= MIX_S;
341 if (mixer_control & 0x00000010) ret |= MIX_S_RAMP;
342 if (mixer_control & 0x00010000) ret |= MIX_AUXA_L;
343 if (mixer_control & 0x00020000) ret |= MIX_AUXA_R;
344 if (mixer_control & 0x00040000) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP;
345 if (mixer_control & 0x00080000) ret |= MIX_AUXA_S;
346 if (mixer_control & 0x00100000) ret |= MIX_AUXA_S_RAMP;
347 if (mixer_control & 0x00200000) ret |= MIX_AUXB_L;
348 if (mixer_control & 0x00400000) ret |= MIX_AUXB_R;
349 if (mixer_control & 0x00800000) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP;
350 if (mixer_control & 0x01000000) ret |= MIX_AUXB_S;
351 if (mixer_control & 0x02000000) ret |= MIX_AUXB_S_RAMP;
352 if (mixer_control & 0x04000000) ret |= MIX_AUXC_L;
353 if (mixer_control & 0x08000000) ret |= MIX_AUXC_R;
354 if (mixer_control & 0x10000000) ret |= MIX_AUXC_L_RAMP | MIX_AUXC_R_RAMP;
355 if (mixer_control & 0x20000000) ret |= MIX_AUXC_S;
356 if (mixer_control & 0x40000000) ret |= MIX_AUXC_S_RAMP;
357
358 return (AXMixControl)ret;
359}
360
361void CUCode_AXWii::GenerateVolumeRamp(u16* output, u16 vol1, u16 vol2, size_t nvals)
362{
363 float curr = vol1;
364 for (size_t i = 0; i < nvals; ++i)
365 {
366 curr += (vol2 - vol1) / (float)nvals;
367 output[i] = curr;
368 }
369}
370
371bool CUCode_AXWii::ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* updates,
372 u32* updates_addr)
373{
374 u16* pb_mem = (u16*)&pb;
375
376 if (!m_old_axwii)
377 return false;
378
379 // Copy the num_updates field.
380 memcpy(num_updates, pb_mem + 41, 6);
381
382 // Get the address of the updates data
383 u16 addr_hi = pb_mem[44];
384 u16 addr_lo = pb_mem[45];
385 u32 addr = HILO_TO_32(addr)((addr_hi << 16) | addr_lo);
386 u16* ptr = (u16*)HLEMemory_Get_Pointer(addr);
387
388 *updates_addr = addr;
389
390 // Copy the updates data and change the offset to match a PB without
391 // updates data.
392 u32 updates_count = num_updates[0] + num_updates[1] + num_updates[2];
393 for (u32 i = 0; i < updates_count; ++i)
394 {
395 u16 update_off = Common::swap16(ptr[2 * i]);
396 u16 update_val = Common::swap16(ptr[2 * i + 1]);
397
398 if (update_off > 45)
399 update_off -= 5;
400
401 updates[2 * i] = update_off;
402 updates[2 * i + 1] = update_val;
403 }
404
405 // Remove the updates data from the PB
406 memmove(pb_mem + 41, pb_mem + 46, sizeof (pb) - 2 * 46);
407
408 return true;
409}
410
411void CUCode_AXWii::ReinjectUpdatesFields(AXPBWii& pb, u16* num_updates, u32 updates_addr)
412{
413 u16* pb_mem = (u16*)&pb;
414
415 // Make some space
416 memmove(pb_mem + 46, pb_mem + 41, sizeof (pb) - 2 * 46);
417
418 // Reinsert previous values
419 pb_mem[41] = num_updates[0];
420 pb_mem[42] = num_updates[1];
421 pb_mem[43] = num_updates[2];
422 pb_mem[44] = updates_addr >> 16;
423 pb_mem[45] = updates_addr & 0xFFFF;
424}
425
426void CUCode_AXWii::ProcessPBList(u32 pb_addr)
427{
428 AXPBWii pb;
429
430 while (pb_addr)
431 {
432 AXBuffers buffers = {{
433 m_samples_left,
434 m_samples_right,
435 m_samples_surround,
436 m_samples_auxA_left,
437 m_samples_auxA_right,
438 m_samples_auxA_surround,
439 m_samples_auxB_left,
440 m_samples_auxB_right,
441 m_samples_auxB_surround,
442 m_samples_auxC_left,
443 m_samples_auxC_right,
444 m_samples_auxC_surround,
445 m_samples_wm0,
446 m_samples_aux0,
447 m_samples_wm1,
448 m_samples_aux1,
449 m_samples_wm2,
450 m_samples_aux2,
451 m_samples_wm3,
452 m_samples_aux3
453 }};
454
455 if (!ReadPB(pb_addr, pb))
456 break;
457
458 u16 num_updates[3];
459 u16 updates[1024];
460 u32 updates_addr;
461 if (ExtractUpdatesFields(pb, num_updates, updates, &updates_addr))
462 {
463 for (int curr_ms = 0; curr_ms < 3; ++curr_ms)
464 {
465 ApplyUpdatesForMs(curr_ms, (u16*)&pb, num_updates, updates);
466 ProcessVoice(pb, buffers, 32,
467 ConvertMixerControl(HILO_TO_32(pb.mixer_control)((pb.mixer_control_hi << 16) | pb.mixer_control_lo)),
468 m_coeffs_available ? m_coeffs : NULL__null);
469
470 // Forward the buffers
471 for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i)
472 buffers.ptrs[i] += 32;
473 }
474 ReinjectUpdatesFields(pb, num_updates, updates_addr);
475 }
476 else
477 {
478 ProcessVoice(pb, buffers, 96,
479 ConvertMixerControl(HILO_TO_32(pb.mixer_control)((pb.mixer_control_hi << 16) | pb.mixer_control_lo)),
480 m_coeffs_available ? m_coeffs : NULL__null);
481 }
482
483 WritePB(pb_addr, pb);
484 pb_addr = HILO_TO_32(pb.next_pb)((pb.next_pb_hi << 16) | pb.next_pb_lo);
485 }
486}
487
488void CUCode_AXWii::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 volume)
489{
490 u16 volume_ramp[96];
491 GenerateVolumeRamp(volume_ramp, m_last_aux_volumes[aux_id], volume, 96);
492 m_last_aux_volumes[aux_id] = volume;
493
494 int* buffers[3] = { 0 };
495 int* main_buffers[3] = {
496 m_samples_left,
497 m_samples_right,
498 m_samples_surround
499 };
500
501 switch (aux_id)
1
'Default' branch taken. Execution continues on line 523
502 {
503 case 0:
504 buffers[0] = m_samples_auxA_left;
505 buffers[1] = m_samples_auxA_right;
506 buffers[2] = m_samples_auxA_surround;
507 break;
508
509 case 1:
510 buffers[0] = m_samples_auxB_left;
511 buffers[1] = m_samples_auxB_right;
512 buffers[2] = m_samples_auxB_surround;
513 break;
514
515 case 2:
516 buffers[0] = m_samples_auxC_left;
517 buffers[1] = m_samples_auxC_right;
518 buffers[2] = m_samples_auxC_surround;
519 break;
520 }
521
522 // Send the content of AUX buffers to the CPU
523 if (write_addr)
2
Assuming 'write_addr' is not equal to 0
3
Taking true branch
524 {
525 int* ptr = (int*)HLEMemory_Get_Pointer(write_addr);
526 for (u32 i = 0; i < 3; ++i)
4
Loop condition is true. Entering loop body
527 for (u32 j = 0; j < 3 * 32; ++j)
5
Loop condition is true. Entering loop body
528 *ptr++ = Common::swap32(buffers[i][j]);
6
Array access results in a null pointer dereference
529 }
530
531 // Then read the buffers from the CPU and add to our main buffers.
532 int* ptr = (int*)HLEMemory_Get_Pointer(read_addr);
533 for (u32 i = 0; i < 3; ++i)
534 for (u32 j = 0; j < 3 * 32; ++j)
535 {
536 s64 sample = (s64)(s32)Common::swap32(*ptr++);
537 sample *= volume_ramp[j];
538 main_buffers[i][j] += (s32)(sample >> 15);
539 }
540}
541
542void CUCode_AXWii::UploadAUXMixLRSC(int aux_id, u32* addresses, u16 volume)
543{
544 int* aux_left = aux_id ? m_samples_auxB_left : m_samples_auxA_left;
545 int* aux_right = aux_id ? m_samples_auxB_right : m_samples_auxA_right;
546 int* aux_surround = aux_id ? m_samples_auxB_surround : m_samples_auxA_surround;
547 int* auxc_buffer = aux_id ? m_samples_auxC_surround : m_samples_auxC_right;
548
549 int* upload_ptr = (int*)HLEMemory_Get_Pointer(addresses[0]);
550 for (u32 i = 0; i < 96; ++i)
551 *upload_ptr++ = Common::swap32(aux_left[i]);
552 for (u32 i = 0; i < 96; ++i)
553 *upload_ptr++ = Common::swap32(aux_right[i]);
554 for (u32 i = 0; i < 96; ++i)
555 *upload_ptr++ = Common::swap32(aux_surround[i]);
556
557 upload_ptr = (int*)HLEMemory_Get_Pointer(addresses[1]);
558 for (u32 i = 0; i < 96; ++i)
559 *upload_ptr++ = Common::swap32(auxc_buffer[i]);
560
561 u16 volume_ramp[96];
562 GenerateVolumeRamp(volume_ramp, m_last_aux_volumes[aux_id], volume, 96);
563 m_last_aux_volumes[aux_id] = volume;
564
565 int* mix_dest[4] = {
566 m_samples_left,
567 m_samples_right,
568 m_samples_surround,
569 m_samples_auxC_left
570 };
571 for (u32 mix_i = 0; mix_i < 4; ++mix_i)
572 {
573 int* dl_ptr = (int*)HLEMemory_Get_Pointer(addresses[2 + mix_i]);
574 for (u32 i = 0; i < 96; ++i)
575 aux_left[i] = Common::swap32(dl_ptr[i]);
576
577 for (u32 i = 0; i < 96; ++i)
578 {
579 s64 sample = (s64)(s32)aux_left[i];
580 sample *= volume_ramp[i];
581 mix_dest[mix_i][i] += (s32)(sample >> 15);
582 }
583 }
584}
585
586void CUCode_AXWii::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume,
587 bool upload_auxc)
588{
589 u16 volume_ramp[96];
590 GenerateVolumeRamp(volume_ramp, m_last_main_volume, volume, 96);
591 m_last_main_volume = volume;
592
593 int upload_buffer[3 * 32] = { 0 };
594
595 for (u32 i = 0; i < 3 * 32; ++i)
596 upload_buffer[i] = Common::swap32(m_samples_surround[i]);
597 memcpy(HLEMemory_Get_Pointer(surround_addr), upload_buffer, sizeof (upload_buffer));
598
599 if (upload_auxc)
600 {
601 surround_addr += sizeof (upload_buffer);
602 for (u32 i = 0; i < 3 * 32; ++i)
603 upload_buffer[i] = Common::swap32(m_samples_auxC_left[i]);
604 memcpy(HLEMemory_Get_Pointer(surround_addr), upload_buffer, sizeof (upload_buffer));
605 }
606
607 short buffer[3 * 32 * 2];
608
609 // Clamp internal buffers to 16 bits.
610 for (u32 i = 0; i < 3 * 32; ++i)
611 {
612 int left = m_samples_left[i];
613 int right = m_samples_right[i];
614
615 // Apply global volume. Cast to s64 to avoid overflow.
616 left = ((s64)left * volume_ramp[i]) >> 15;
617 right = ((s64)right * volume_ramp[i]) >> 15;
618
619 if (left < -32767) left = -32767;
620 if (left > 32767) left = 32767;
621 if (right < -32767) right = -32767;
622 if (right > 32767) right = 32767;
623
624 m_samples_left[i] = left;
625 m_samples_right[i] = right;
626 }
627
628 for (u32 i = 0; i < 3 * 32; ++i)
629 {
630 buffer[2 * i] = Common::swap16(m_samples_right[i]);
631 buffer[2 * i + 1] = Common::swap16(m_samples_left[i]);
632 }
633
634 memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof (buffer));
635
636 // There should be a DSP_SYNC message sent here. However, it looks like not
637 // sending it does not cause any issue, and sending it actually causes some
638 // sounds to go at half speed. I have no idea why.
639}
640
641void CUCode_AXWii::OutputWMSamples(u32* addresses)
642{
643 int* buffers[] = {
644 m_samples_wm0,
645 m_samples_wm1,
646 m_samples_wm2,
647 m_samples_wm3
648 };
649
650 for (u32 i = 0; i < 4; ++i)
651 {
652 int* in = buffers[i];
653 u16* out = (u16*)HLEMemory_Get_Pointer(addresses[i]);
654 for (u32 j = 0; j < 3 * 6; ++j)
655 {
656 int sample = in[j];
657 if (sample < -32767) sample = -32767;
658 if (sample > 32767) sample = 32767;
659 out[j] = Common::swap16((u16)sample);
660 }
661 }
662}
663
664u32 CUCode_AXWii::GetUpdateMs()
665{
666 return 3;
667}
668
669void CUCode_AXWii::DoState(PointerWrap &p)
670{
671 std::lock_guard<std::mutex> lk(m_processing);
672
673 DoStateShared(p);
674 DoAXState(p);
675
676 p.Do(m_samples_auxC_left);
677 p.Do(m_samples_auxC_right);
678 p.Do(m_samples_auxC_surround);
679
680 p.Do(m_samples_wm0);
681 p.Do(m_samples_wm1);
682 p.Do(m_samples_wm2);
683 p.Do(m_samples_wm3);
684
685 p.Do(m_samples_aux0);
686 p.Do(m_samples_aux1);
687 p.Do(m_samples_aux2);
688 p.Do(m_samples_aux3);
689
690 p.Do(m_last_main_volume);
691 p.Do(m_last_aux_volumes);
692}