forked from PAWPAW-Mirror/lib_xua
Async feedback system re-implemented to allow for MasterClock/SampleRate ration not being a power of 2 e.g. 32000Hz from 24.576MHz MClk.
This commit is contained in:
@@ -45,8 +45,12 @@ extern unsigned char mixSel[MAX_MIX_COUNT][MIX_INPUTS];
|
|||||||
|
|
||||||
/* Global var for current frequency, set to default freq */
|
/* Global var for current frequency, set to default freq */
|
||||||
unsigned int g_curSamFreq = DEFAULT_FREQ;
|
unsigned int g_curSamFreq = DEFAULT_FREQ;
|
||||||
unsigned int g_curSamFreq48000Family = DEFAULT_FREQ % 48000 == 0;
|
//unsigned int g_curSamFreq48000Family = DEFAULT_FREQ % 48000 == 0;
|
||||||
unsigned int g_curSamFreqMultiplier = (DEFAULT_FREQ * 512 * 4) / (DEFAULT_MCLK_FREQ);
|
|
||||||
|
#if 0
|
||||||
|
/* Original feedback implementation */
|
||||||
|
long long g_curSamFreqMultiplier = (DEFAULT_FREQ * 512 * 4) / (DEFAULT_MCLK_FREQ);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Store an int into a char array: Note this allows non-word aligned access unlike reinerpret cast */
|
/* Store an int into a char array: Note this allows non-word aligned access unlike reinerpret cast */
|
||||||
static void storeInt(unsigned char buffer[], int index, int val)
|
static void storeInt(unsigned char buffer[], int index, int val)
|
||||||
@@ -113,9 +117,19 @@ static unsigned longMul(unsigned a, unsigned b, int prec)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setG_curSamFreqMultiplier(int x) {
|
#if 0
|
||||||
asm(" stw %0, dp[g_curSamFreqMultiplier]" :: "r"(x));
|
/* Original feedback implementation */
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
unsigned * unsafe curSamFreqMultiplier = &g_curSamFreqMultiplier;
|
||||||
|
|
||||||
|
static void setG_curSamFreqMultiplier(unsigned x)
|
||||||
|
{
|
||||||
|
// asm(" stw %0, dp[g_curSamFreqMultiplier]" :: "r"(x));
|
||||||
|
*curSamFreqMultiplier = x;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Update master volume i.e. i.e update weights for all channels */
|
/* Update master volume i.e. i.e update weights for all channels */
|
||||||
static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
|
static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
|
||||||
@@ -261,8 +275,7 @@ static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
|
|||||||
int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl
|
int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
unsigned char buffer[128];
|
unsigned char buffer[512];
|
||||||
int i_tmp;
|
|
||||||
int unitID;
|
int unitID;
|
||||||
XUD_Result_t result;
|
XUD_Result_t result;
|
||||||
unsigned datalength;
|
unsigned datalength;
|
||||||
@@ -302,27 +315,29 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
if(datalength == 4)
|
if(datalength == 4)
|
||||||
{
|
{
|
||||||
/* Re-construct Sample Freq */
|
/* Re-construct Sample Freq */
|
||||||
i_tmp = buffer[0] | (buffer[1] << 8) | buffer[2] << 16 | buffer[3] << 24;
|
int newSampleRate = buffer[0] | (buffer[1] << 8) | buffer[2] << 16 | buffer[3] << 24;
|
||||||
|
|
||||||
/* Instruct audio thread to change sample freq (if change required) */
|
/* Instruct audio thread to change sample freq (if change required) */
|
||||||
if(i_tmp != g_curSamFreq)
|
if(newSampleRate != g_curSamFreq)
|
||||||
{
|
{
|
||||||
g_curSamFreq = i_tmp;
|
int newMasterClock;
|
||||||
g_curSamFreq48000Family = g_curSamFreq % 48000 == 0;
|
|
||||||
|
g_curSamFreq = newSampleRate;
|
||||||
|
#if 0
|
||||||
|
/* Original feedback implementation */
|
||||||
|
g_curSamFreq48000Family = ((MCLK_48 % g_curSamFreq) == 0);
|
||||||
|
|
||||||
if(g_curSamFreq48000Family)
|
if(g_curSamFreq48000Family)
|
||||||
{
|
{
|
||||||
i_tmp = MCLK_48;
|
newMasterClock = MCLK_48;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
i_tmp = MCLK_441;
|
newMasterClock = MCLK_441;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned mult = (g_curSamFreq*512*4)/i_tmp;
|
setG_curSamFreqMultiplier(g_curSamFreq/(newMasterClock/512));
|
||||||
setG_curSamFreqMultiplier(mult);
|
#endif
|
||||||
|
|
||||||
asm("ecallf %0"::"r"(mult));
|
|
||||||
#ifdef ADAT_RX
|
#ifdef ADAT_RX
|
||||||
/* Configure ADAT SMUX based on sample rate */
|
/* Configure ADAT SMUX based on sample rate */
|
||||||
outuint(c_clk_ctl, SET_SMUX);
|
outuint(c_clk_ctl, SET_SMUX);
|
||||||
@@ -845,8 +860,8 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
int i = 2;
|
int i = 2;
|
||||||
|
|
||||||
#ifndef SAMPLE_RATE_LIST
|
#ifndef SAMPLE_RATE_LIST
|
||||||
int currentFreq44 = MIN_FREQ_44;
|
int currentFreq44 = 11025; //MIN_FREQ_44;
|
||||||
int currentFreq48 = MIN_FREQ_48;
|
int currentFreq48 = 8000; //MIN_FREQ_48;
|
||||||
unsigned maxFreq = MAX_FREQ;
|
unsigned maxFreq = MAX_FREQ;
|
||||||
|
|
||||||
#if defined (FULL_SPEED_AUDIO_2)
|
#if defined (FULL_SPEED_AUDIO_2)
|
||||||
@@ -858,6 +873,21 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
maxFreq = MAX_FREQ_FS;
|
maxFreq = MAX_FREQ_FS;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
/* Special case for some low sample rates */
|
||||||
|
unsigned lowSampleRateList[] = {8000, 11025, 12000, 16000, 22050, 32000};
|
||||||
|
|
||||||
|
for (int k = 0; k < sizeof(lowSampleRateList)/sizeof(unsigned); k++)
|
||||||
|
{
|
||||||
|
if((lowSampleRateList[k] >= MIN_FREQ) && (lowSampleRateList[k] <= MAX_FREQ))
|
||||||
|
{
|
||||||
|
storeFreq(buffer, i, lowSampleRateList[k]);
|
||||||
|
num_freqs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Just keep doubling for standard freqs >= 44.1/48kHz */
|
||||||
|
currentFreq44 = 44100;
|
||||||
|
currentFreq48 = 48000;
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
if((currentFreq44 <= maxFreq) && (currentFreq44 >= MIN_FREQ))
|
if((currentFreq44 <= maxFreq) && (currentFreq44 >= MIN_FREQ))
|
||||||
@@ -1071,31 +1101,37 @@ int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp
|
|||||||
if((sp.wLength == 3) && (length == 3))
|
if((sp.wLength == 3) && (length == 3))
|
||||||
{
|
{
|
||||||
/* Recontruct sample-freq */
|
/* Recontruct sample-freq */
|
||||||
int i_tmp = buffer[0] | (buffer [1] << 8) | (buffer[2] << 16);
|
int newSampleRate = buffer[0] | (buffer [1] << 8) | (buffer[2] << 16);
|
||||||
|
|
||||||
if(i_tmp != g_curSamFreq)
|
if(newSampleRate != g_curSamFreq)
|
||||||
{
|
{
|
||||||
int curSamFreq44100Family;
|
int curSamFreq44100Family;
|
||||||
|
int curSamFreq48000Family;
|
||||||
|
|
||||||
/* Windows Audio Class driver has a nice habbit of sending invalid SF's (e.g. 48001Hz)
|
/* Windows Audio Class driver has a nice habbit of sending invalid SF's (e.g. 48001Hz)
|
||||||
* when under stress. Lets double check it here and ignore if not valid. */
|
* when under stress. Lets double check it here and ignore if not valid. */
|
||||||
g_curSamFreq48000Family = i_tmp % 48000 == 0;
|
curSamFreq48000Family = newSampleRate % 48000 == 0;
|
||||||
curSamFreq44100Family = i_tmp % 44100 == 0;
|
curSamFreq44100Family = newSampleRate % 44100 == 0;
|
||||||
|
|
||||||
if(g_curSamFreq48000Family || curSamFreq44100Family)
|
(curSamFreq48000Family || curSamFreq44100Family)
|
||||||
{
|
{
|
||||||
g_curSamFreq = i_tmp;
|
#if 0
|
||||||
|
/* Original feedback implementation */
|
||||||
|
|
||||||
|
int newMasterClock;
|
||||||
|
g_curSamFreq = newSamplerate;
|
||||||
|
|
||||||
if(g_curSamFreq48000Family)
|
if(g_curSamFreq48000Family)
|
||||||
{
|
{
|
||||||
i_tmp = MCLK_48;
|
newMasterClock = MCLK_48;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
i_tmp = MCLK_441;
|
newMasterClock = MCLK_441;
|
||||||
}
|
}
|
||||||
|
|
||||||
setG_curSamFreqMultiplier((g_curSamFreq*512*4)/i_tmp);
|
setG_curSamFreqMultiplier((g_curSamFreq*512*4)/newMasterClock);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Instruct audio thread to change sample freq */
|
/* Instruct audio thread to change sample freq */
|
||||||
outuint(c_audioControl, SET_SAMPLE_FREQ);
|
outuint(c_audioControl, SET_SAMPLE_FREQ);
|
||||||
|
|||||||
@@ -160,10 +160,13 @@ void buffer(register chanend c_aud_out, register chanend c_aud_in,
|
|||||||
XUD_ep ep_hid = XUD_InitEp(c_hid);
|
XUD_ep ep_hid = XUD_InitEp(c_hid);
|
||||||
#endif
|
#endif
|
||||||
unsigned u_tmp;
|
unsigned u_tmp;
|
||||||
unsigned sampleFreq = 0;
|
unsigned sampleFreq = DEFAULT_FREQ;
|
||||||
|
unsigned masterClockFreq = DEFAULT_MCLK_FREQ;
|
||||||
unsigned lastClock = 0;
|
unsigned lastClock = 0;
|
||||||
|
|
||||||
unsigned clocks = 0;
|
unsigned clocks = 0;
|
||||||
|
long long clockcounter = 0;
|
||||||
|
|
||||||
|
|
||||||
#if (NUM_USB_CHAN_IN > 0)
|
#if (NUM_USB_CHAN_IN > 0)
|
||||||
unsigned bufferIn = 1;
|
unsigned bufferIn = 1;
|
||||||
@@ -172,6 +175,7 @@ void buffer(register chanend c_aud_out, register chanend c_aud_in,
|
|||||||
unsigned sofCount = 0;
|
unsigned sofCount = 0;
|
||||||
unsigned freqChange = 0;
|
unsigned freqChange = 0;
|
||||||
|
|
||||||
|
unsigned mod_from_last_time = 0;
|
||||||
#ifdef FB_TOLERANCE_TEST
|
#ifdef FB_TOLERANCE_TEST
|
||||||
unsigned expected_fb = 0;
|
unsigned expected_fb = 0;
|
||||||
#endif
|
#endif
|
||||||
@@ -317,13 +321,21 @@ void buffer(register chanend c_aud_out, register chanend c_aud_in,
|
|||||||
sofCount = 0;
|
sofCount = 0;
|
||||||
clocks = 0;
|
clocks = 0;
|
||||||
remnant = 0;
|
remnant = 0;
|
||||||
|
clockcounter = 0;
|
||||||
|
|
||||||
/* Set g_speed to something sensible. We expect it to get over-written before stream time */
|
/* Set g_speed to something sensible. We expect it to get over-written before stream time */
|
||||||
int min, mid, max;
|
int min, mid, max;
|
||||||
GetADCCounts(sampleFreq, min, mid, max);
|
GetADCCounts(sampleFreq, min, mid, max);
|
||||||
g_speed = mid<<16;
|
g_speed = mid<<16;
|
||||||
|
|
||||||
|
if((MCLK_48 % sampleFreq) == 0)
|
||||||
|
{
|
||||||
|
masterClockFreq = MCLK_48;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
masterClockFreq = MCLK_441;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* Ideally we want to wait for handshake (and pass back up) here. But we cannot keep this
|
/* Ideally we want to wait for handshake (and pass back up) here. But we cannot keep this
|
||||||
* core locked, it must stay responsive to packets (MIDI etc) and SOFs. So, set a flag and check for
|
* core locked, it must stay responsive to packets (MIDI etc) and SOFs. So, set a flag and check for
|
||||||
@@ -400,17 +412,18 @@ void buffer(register chanend c_aud_out, register chanend c_aud_in,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
unsigned mask = MASK_16_13, usb_speed;
|
unsigned usb_speed;
|
||||||
|
|
||||||
GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed);
|
GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
unsigned mask = MASK_16_13;
|
||||||
|
/* Original feedback implementation */
|
||||||
if(usb_speed != XUD_SPEED_HS)
|
if(usb_speed != XUD_SPEED_HS)
|
||||||
mask = MASK_16_10;
|
mask = MASK_16_10;
|
||||||
|
|
||||||
/* Number of MCLKS this SOF, approx 125 * 24 (3000), sample by sample rate */
|
/* Number of MCLKS this SOF, approx 125 * 24 (3000), sample by sample rate */
|
||||||
GET_SHARED_GLOBAL(cycles, g_curSamFreqMultiplier);
|
GET_SHARED_GLOBAL(cycles, g_curSamFreqMultiplier);
|
||||||
cycles = ((int)((short)(u_tmp - lastClock))) * cycles;
|
cycles = ((int)((short)(u_tmp - lastClock))) * cycles;
|
||||||
cycles = (int) cycles >> 2; /* /4 */
|
|
||||||
|
|
||||||
/* Any odd bits (lower than 16.23) have to be kept seperate */
|
/* Any odd bits (lower than 16.23) have to be kept seperate */
|
||||||
remnant += cycles & mask;
|
remnant += cycles & mask;
|
||||||
@@ -436,9 +449,11 @@ void buffer(register chanend c_aud_out, register chanend c_aud_in,
|
|||||||
{
|
{
|
||||||
int usb_speed;
|
int usb_speed;
|
||||||
asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks
|
asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks
|
||||||
|
|
||||||
GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed);
|
GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed);
|
||||||
|
|
||||||
|
|
||||||
|
printhexln(clocks);
|
||||||
|
|
||||||
if (usb_speed == XUD_SPEED_HS)
|
if (usb_speed == XUD_SPEED_HS)
|
||||||
{
|
{
|
||||||
(fb_clocks, unsigned[])[0] = clocks;
|
(fb_clocks, unsigned[])[0] = clocks;
|
||||||
@@ -455,6 +470,63 @@ void buffer(register chanend c_aud_out, register chanend c_aud_in,
|
|||||||
#endif
|
#endif
|
||||||
clocks = 0;
|
clocks = 0;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
/* Assuming 48kHz from a 24.576 master clock (0.0407uS period)
|
||||||
|
* MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF.
|
||||||
|
* expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format.
|
||||||
|
* Average over 128 SOFs - 128 x 3072 = 0x60000.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) */
|
||||||
|
int count = (int) ((short)(u_tmp - lastClock));
|
||||||
|
|
||||||
|
unsigned long long full_result = count *64ULL * sampleFreq;
|
||||||
|
|
||||||
|
clockcounter += full_result;
|
||||||
|
|
||||||
|
/* Store MCLK for next time around... */
|
||||||
|
lastClock = u_tmp;
|
||||||
|
|
||||||
|
/* Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll
|
||||||
|
* We always count 128 SOFs, so 16ms @ HS, 128ms @ FS */
|
||||||
|
if(sofCount == 128)
|
||||||
|
{
|
||||||
|
sofCount = 0;
|
||||||
|
|
||||||
|
clockcounter += mod_from_last_time;
|
||||||
|
clocks = clockcounter / masterClockFreq;
|
||||||
|
mod_from_last_time = clockcounter % masterClockFreq;
|
||||||
|
|
||||||
|
clocks <<=3;
|
||||||
|
|
||||||
|
#ifdef FB_TOLERANCE_TEST
|
||||||
|
if (clocks > (expected_fb - FB_TOLERANCE) &&
|
||||||
|
clocks < (expected_fb + FB_TOLERANCE))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
int usb_speed;
|
||||||
|
asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks
|
||||||
|
|
||||||
|
GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed);
|
||||||
|
|
||||||
|
//printhexln(clocks);
|
||||||
|
if (usb_speed == XUD_SPEED_HS)
|
||||||
|
{
|
||||||
|
(fb_clocks, unsigned[])[0] = clocks;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(fb_clocks, unsigned[])[0] = clocks>>2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef FB_TOLERANCE_TEST
|
||||||
|
else
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
clockcounter = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
sofCount++;
|
sofCount++;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user