From b29cdef8ecd15bc4d333b021b11a6ee4a1dd483e Mon Sep 17 00:00:00 2001
From: FIX94 <fix94.1@gmail.com>
Date: Mon, 21 Nov 2016 22:47:29 +0100
Subject: [PATCH] (WiiU) continuation of the audio driver changes from
 yesterday

---
 audio/drivers/wiiu_audio.c        | 91 +++++++++++++------------------
 wiiu/multivoice.h                 | 20 +++++++
 wiiu/system/exports/libsndcore2.h |  7 +++
 3 files changed, 64 insertions(+), 54 deletions(-)
 create mode 100644 wiiu/multivoice.h

diff --git a/audio/drivers/wiiu_audio.c b/audio/drivers/wiiu_audio.c
index 56f882e105..d85b31052f 100644
--- a/audio/drivers/wiiu_audio.c
+++ b/audio/drivers/wiiu_audio.c
@@ -29,6 +29,7 @@
 
 #include "wiiu/wiiu_dbg.h"
 #include "wiiu/system/memory.h"
+#include "wiiu/multivoice.h"
 
 #include "audio/audio_driver.h"
 #include "configuration.h"
@@ -37,8 +38,7 @@
 
 typedef struct
 {
-   AXVoice* voice_l;
-   AXVoice* voice_r;
+   AXMVoice* mvoice;
    uint16_t* buffer_l;
    uint16_t* buffer_r;
    bool nonblocking;
@@ -72,12 +72,11 @@ AXResult ax_aux_callback(void* data, ax_audio_t* ax)
    OSUninterruptibleSpinLock_Acquire(&ax->spinlock);
    //buffer underrun, stop playback to let if fill up
    if(ax->written < AX_AUDIO_SAMPLE_MIN)
-   {
-      AXSetVoiceState(ax->voice_l, AX_VOICE_STATE_STOPPED);
-      AXSetVoiceState(ax->voice_r, AX_VOICE_STATE_STOPPED);
-   }
-   else //all good, play back frame
-      ax->written -= AX_AUDIO_SAMPLE_COUNT;
+      AXSetMultiVoiceState(ax->mvoice, AX_VOICE_STATE_STOPPED);
+   //make sure to update written value if voice is running
+   if(AXIsMultiVoiceRunning(ax->mvoice))
+      ax->written -= (ax->written < AX_AUDIO_SAMPLE_COUNT ? ax->written : AX_AUDIO_SAMPLE_COUNT);
+
    OSUninterruptibleSpinLock_Release(&ax->spinlock);
    return AX_RESULT_SUCCESS;
 }
@@ -93,10 +92,11 @@ static void* ax_audio_init(const char* device, unsigned rate, unsigned latency)
 
    AXInitWithParams(&init);
 
-   ax->voice_l = AXAcquireVoice(10, NULL, ax);
-   ax->voice_r = AXAcquireVoice(10, NULL, ax);
+   u16 setup_buf[0x30] = {0};
+   setup_buf[0x25] = 2; //we request 2 channels
+   AXAcquireMultiVoice(31, NULL, 0, setup_buf, &ax->mvoice);
 
-   if (!ax->voice_l || !ax->voice_r)
+   if (!ax->mvoice || ax->mvoice->channels != 2)
    {
       free(ax);
       return NULL;
@@ -109,37 +109,37 @@ static void* ax_audio_init(const char* device, unsigned rate, unsigned latency)
    DCFlushRange(ax->buffer_l,AX_AUDIO_SIZE);
    DCFlushRange(ax->buffer_r,AX_AUDIO_SIZE);
 
+   //shared by both voices
    AXVoiceOffsets offsets;
-
-   offsets.data = ax->buffer_l;
    offsets.currentOffset = 0;
    offsets.loopOffset = 0;
    offsets.endOffset = AX_AUDIO_COUNT - 1;
    offsets.loopingEnabled = AX_VOICE_LOOP_ENABLED;
    offsets.dataType = AX_VOICE_FORMAT_LPCM16;
-   AXSetVoiceOffsets(ax->voice_l, &offsets);
+
+   offsets.data = ax->buffer_l;
+   AXSetVoiceOffsets(ax->mvoice->v[0], &offsets);
 
    offsets.data = ax->buffer_r;
-   AXSetVoiceOffsets(ax->voice_r, &offsets);
+   AXSetVoiceOffsets(ax->mvoice->v[1], &offsets);
+
+   AXSetMultiVoiceSrcType(ax->mvoice, AX_VOICE_SRC_TYPE_NONE);
+   AXSetMultiVoiceSrcRatio(ax->mvoice, 1.0f);
+
+   AXVoiceVeData ve = {0xF000, 0};
+   AXSetMultiVoiceVe(ax->mvoice, &ve);
 
-   AXSetVoiceSrcType(ax->voice_l, AX_VOICE_SRC_TYPE_NONE);
-   AXSetVoiceSrcType(ax->voice_r, AX_VOICE_SRC_TYPE_NONE);
-   AXSetVoiceSrcRatio(ax->voice_l, 1.0f);
-   AXSetVoiceSrcRatio(ax->voice_r, 1.0f);
-   AXVoiceVeData ve = {0xFFFF, 0};
-   AXSetVoiceVe(ax->voice_l, &ve);
-   AXSetVoiceVe(ax->voice_r, &ve);
    u32 mix[24] = {0};
    mix[0] = 0x80000000;
-   AXSetVoiceDeviceMix(ax->voice_l, AX_DEVICE_TYPE_DRC, 0, (AXVoiceDeviceMixData*)mix);
-   AXSetVoiceDeviceMix(ax->voice_l, AX_DEVICE_TYPE_TV, 0, (AXVoiceDeviceMixData*)mix);
+   AXSetVoiceDeviceMix(ax->mvoice->v[0], AX_DEVICE_TYPE_DRC, 0, (AXVoiceDeviceMixData*)mix);
+   AXSetVoiceDeviceMix(ax->mvoice->v[0], AX_DEVICE_TYPE_TV, 0, (AXVoiceDeviceMixData*)mix);
+
    mix[0] = 0;
    mix[4] = 0x80000000;
-   AXSetVoiceDeviceMix(ax->voice_r, AX_DEVICE_TYPE_DRC, 0, (AXVoiceDeviceMixData*)mix);
-   AXSetVoiceDeviceMix(ax->voice_r, AX_DEVICE_TYPE_TV, 0, (AXVoiceDeviceMixData*)mix);
+   AXSetVoiceDeviceMix(ax->mvoice->v[1], AX_DEVICE_TYPE_DRC, 0, (AXVoiceDeviceMixData*)mix);
+   AXSetVoiceDeviceMix(ax->mvoice->v[1], AX_DEVICE_TYPE_TV, 0, (AXVoiceDeviceMixData*)mix);
 
-   AXSetVoiceState(ax->voice_l, AX_VOICE_STATE_STOPPED);
-   AXSetVoiceState(ax->voice_r, AX_VOICE_STATE_STOPPED);
+   AXSetMultiVoiceState(ax->mvoice, AX_VOICE_STATE_STOPPED);
 
    ax->pos = 0;
    ax->written = 0;
@@ -158,7 +158,7 @@ static void ax_audio_free(void* data)
    ax_audio_t* ax = (ax_audio_t*)data;
 
    AXRegisterAuxCallback(AX_DEVICE_TYPE_DRC, 0, 0, NULL, NULL);
-
+   AXFreeMultiVoice(ax->mvoice);
    MEM1_free(ax->buffer_l);
    MEM1_free(ax->buffer_r);
    free(ax);
@@ -213,6 +213,8 @@ static ssize_t ax_audio_write(void* data, const void* buf, size_t size)
       count = 0;
       goto wiiu_audio_end;
    }
+   if(count > AX_AUDIO_COUNT)
+      count = AX_AUDIO_COUNT;
 
    size_t countAvail = AX_AUDIO_COUNT - ax->written;
    if (ax->nonblocking)
@@ -230,8 +232,8 @@ static ssize_t ax_audio_write(void* data, const void* buf, size_t size)
       //sync, wait for free memory
       do {
          OSYieldThread();
-		 countAvail = AX_AUDIO_COUNT - ax->written;
-      } while(AXIsVoiceRunning(ax->voice_l) && countAvail < count);
+         countAvail = AX_AUDIO_COUNT - ax->written;
+      } while(AXIsMultiVoiceRunning(ax->mvoice) && countAvail < count);
    }
 
 //   ax_audio_buffer_write(ax, buf, count);
@@ -271,7 +273,7 @@ static ssize_t ax_audio_write(void* data, const void* buf, size_t size)
    OSUninterruptibleSpinLock_Release(&ax->spinlock);
 
    //possibly buffer underrun
-   if(!AXIsVoiceRunning(ax->voice_l))
+   if(!AXIsMultiVoiceRunning(ax->mvoice))
    {
       //checks if it can be started
       ax_audio_start(ax);
@@ -287,15 +289,14 @@ static bool ax_audio_stop(void* data)
 {
    ax_audio_t* ax = (ax_audio_t*)data;
 
-   AXSetVoiceState(ax->voice_l, AX_VOICE_STATE_STOPPED);
-   AXSetVoiceState(ax->voice_r, AX_VOICE_STATE_STOPPED);
+   AXSetMultiVoiceState(ax->mvoice, AX_VOICE_STATE_STOPPED);
    return true;
 }
 
 static bool ax_audio_alive(void* data)
 {
    ax_audio_t* ax = (ax_audio_t*)data;
-   return AXIsVoiceRunning(ax->voice_l);
+   return AXIsMultiVoiceRunning(ax->mvoice);
 }
 
 static bool ax_audio_start(void* data)
@@ -308,25 +309,9 @@ static bool ax_audio_start(void* data)
    if (runloop_ctl(RUNLOOP_CTL_IS_SHUTDOWN, NULL))
       return true;
 
-   //for safety first
-   ax_audio_stop(data);
-
-   //reset offset to last load offset
-   AXVoiceOffsets offsets;
-   uint32_t lastOffset = ((ax->pos - ((ax->written)<<1)) & AX_AUDIO_COUNT_MASK);
-   AXGetVoiceOffsets(ax->voice_l, &offsets);
-   offsets.currentOffset = lastOffset;
-   AXSetVoiceOffsets(ax->voice_l, &offsets);
-   AXGetVoiceOffsets(ax->voice_r, &offsets);
-   offsets.currentOffset = lastOffset;
-   AXSetVoiceOffsets(ax->voice_r, &offsets);
-
    //set back to playing on enough buffered data
    if(ax->written > AX_AUDIO_SAMPLE_MIN)
-   {
-      AXSetVoiceState(ax->voice_l, AX_VOICE_STATE_PLAYING);
-      AXSetVoiceState(ax->voice_r, AX_VOICE_STATE_PLAYING);
-   }
+      AXSetMultiVoiceState(ax->mvoice, AX_VOICE_STATE_PLAYING);
 
    return true;
 }
@@ -337,8 +322,6 @@ static void ax_audio_set_nonblock_state(void* data, bool state)
 
    if (ax)
    {
-      if(state != ax->nonblocking)
-         ax_audio_start(data);
       ax->nonblocking = state;
    }
 }
diff --git a/wiiu/multivoice.h b/wiiu/multivoice.h
new file mode 100644
index 0000000000..519d11a6c9
--- /dev/null
+++ b/wiiu/multivoice.h
@@ -0,0 +1,20 @@
+
+#ifndef _MULTIVOICE_H_
+#define _MULTIVOICE_H_
+
+typedef struct
+{
+	bool running;
+	uint32_t channels;
+	AXVoice *v[];
+} AXMVoice;
+
+void AXAcquireMultiVoice(uint32_t prio, void *cb, uint32_t cbarg, void *setup, AXMVoice **mvoice);
+void AXSetMultiVoiceState(AXMVoice *mvoice, AXVoiceState state);
+void AXSetMultiVoiceVe(AXMVoice *mvoice, AXVoiceVeData *veData);
+void AXSetMultiVoiceSrcType(AXMVoice *mvoice, AXVoiceSrcType type);
+void AXSetMultiVoiceSrcRatio(AXMVoice *mvoice, float ratio);
+bool AXIsMultiVoiceRunning(AXMVoice *mvoice);
+void AXFreeMultiVoice(AXMVoice *mvoice);
+
+#endif
diff --git a/wiiu/system/exports/libsndcore2.h b/wiiu/system/exports/libsndcore2.h
index 66b9f2bf5a..d6f30b2443 100644
--- a/wiiu/system/exports/libsndcore2.h
+++ b/wiiu/system/exports/libsndcore2.h
@@ -2,5 +2,12 @@
 EXPORT_BEGIN(sndcore2.rpl);
 
 #include "../rpl/libsndcore2/exports.h"
+EXPORT(AXAcquireMultiVoice);
+EXPORT(AXSetMultiVoiceState);
+EXPORT(AXSetMultiVoiceVe);
+EXPORT(AXSetMultiVoiceSrcType);
+EXPORT(AXSetMultiVoiceSrcRatio);
+EXPORT(AXIsMultiVoiceRunning);
+EXPORT(AXFreeMultiVoice);
 
 EXPORT_END();