Volume Control?

New to XMOS and XCore? Get started here.
User avatar
akp
XCore Expert
Posts: 578
Joined: Thu Nov 26, 2015 11:47 pm

Post by akp »

Of course on reflection I don't know the math Windows, Mac or Linux do, they may well do it crappy.


User avatar
Wavelength
Experienced Member
Posts: 76
Joined: Mon Sep 24, 2018 9:56 pm

Post by Wavelength »

Akp,

Correct this is not a high end audio forum. But it is one of the first XMOS protocols supported. I remember more than 10 years ago when Ali and I spent a couple of days hashing out the first version of the USB->I2S code.

But this could be helpful to designers reading this! DAC chips these days are all single bit, well single bit or up to six bits. The interpolation of PCM data to these streams requires a lot of data. But the interface is still set to 32 bits maximum. So doing 64 bit math in the XMOS is just not useful. In the DAC chip itself though, the interpolation of the input sample to the output bit stream can benefit from use of a volume control there. Just like it's better not to do it in the box regardless if it is Windows which uses a 0-100% signal or Apple which adheres to to whatever the interface warrants.

Really any company who optimizes the entire product with these things in mind will end up with a better product and that is all I am after.

Thanks,
Gordon
Wavelength Audio, ltd.
MaximLiadov
XCore Addict
Posts: 130
Joined: Mon Apr 16, 2018 9:14 am

Post by MaximLiadov »

After 1 year of time-to-time exprerimenting I successfuly have made a very nice hardware volume control inside DAC instead of digital volume control inside XMOS by default. So, yes, guy, it's possible, though not too easy. No, source code sharing makes no sense, as a reference open-source software is not ready for that and need to be rewritten completely from scratches.

Anyway. Some helpful information. Starting point is:

1. Disable digital volume control inside XMOS to exclude double volume changing:
//updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);

2. Getting volume from FU_USBOUT event:
if ((sp.wValue & 0xff) == 1) new_volume = ((signed char)buffer[1])*-2;

where ((sp.wValue & 0xff) == 1) is a magical condition when OS volume is changed exactly.

3. Then use new_volume as absolute volume for you DAC through I2C bus.

I use more advanced technics, as I need to show the current volume on screen too, not only change it.

More advanced problem I faced is in synchronizing my hardware volume knob (encoder) with OS volume slider. So vice versa, from device to host. We see a hint in the source code:

/* Direction: Device-to-host */

If someone knows how to send this kind of event from any part of your source code to AudioClassRequests_2 event handler, please let me know. Any small hint would be very welcome.
User avatar
Wavelength
Experienced Member
Posts: 76
Joined: Mon Sep 24, 2018 9:56 pm

Post by Wavelength »

Maxim,

I developed a product years ago that used HID to update the volume control so that they were both at the same level. When someone changed the rotary knob instead of updating the volume by I2C, I instead sent an HID that the volume had increased or decreased and when I received the call back from the HOST I made the I2C change.

I was informed by Alison @ Apple that a better way to do this was through Status Interrupt calls to the HOST. If you are an apple developer, look under TN2274 USB Audio on the Mac. Now of course I have no idea how Windows handles this as they seem to be pretty far behind the curve on these kind of full prospective of USB specifications.

My way worked fine and it's not creating a bunch of traffic and was easy to implement considering all changes to the volume would come from the HOST. You would also display changes to volume when receiving the indicator from the HOST.

Thanks,
Gordon
Wavelength Audio, ltd.
MaximLiadov
XCore Addict
Posts: 130
Joined: Mon Apr 16, 2018 9:14 am

Post by MaximLiadov »

Thank you, Gordon! That's very nice from you. Yes, you are right. HID is the 100% answer here.

For me it isn't an ideal solution, as my product could work in stand-alone mode just with SPDIF input as a sound source, not only USB. So, it's better for me to find an alternative way. To do not lose ability for customers of direct volume control by I2C bus too. So it's interesting if anyone has even tried and got any success in sending device to host events in particular. I cannot understand yet how to set in queue to drop a message to USB. USB part of firmware looks like a pure nightmare for me, despite the fact I am very skilled in the rest parts. Not my cup of tea. :)
User avatar
Wavelength
Experienced Member
Posts: 76
Joined: Mon Sep 24, 2018 9:56 pm

Post by Wavelength »

Maxim,
Probably the easiest way to do this is if you are attached and selected as SPDIF, then use the I2C from the rotary. If you are connected and active with USB then use HID no matter what the selected input is. If you are selected SPDIF and USB is connected but not active then use I2C and when USB becomes active it will ask for the current setting and provide that to the HOST then you are all set.
I think a bigger problem with sending an Interrupt over endpoint 0 to the host for a feature update is that Windows probably does not support this. They don't support a lot of the Endpoint 0 calls, including user interrupt and so forth that are included in macOS and Linux.
Believe me.... living he!! right now on Windows because of some of the things Windows doesn't support.
If you have a USB analyzer it should be pretty easy to figure out what to do.
Thanks,
Gordon
Wavelength Audio, ltd.
MaximLiadov
XCore Addict
Posts: 130
Joined: Mon Apr 16, 2018 9:14 am

Post by MaximLiadov »

Gordon, thank you. I googled your name and watched your Youtube interview. Very interesting. Is that true that you are the person who invented or took part in invention of USB asynchronous mode? If so, THANK YOU million times from all music industry! Thank you once again for all your advices. It's priceless. It's a big honour.

It's interesting though why we could see /* Direction: Device-to-host */ subsection in firmware. What is it for? Could we use it somehow for common goods?

Code: Select all

                            else /* Direction: Device-to-host */
                            {
                                if(unitID == FU_USBOUT)
                                {
                                    if ((sp.wValue & 0xff) <= NUM_USB_CHAN_OUT)
                                    {
                                        buffer[0] = volsOut[ sp.wValue&0xff ];
                                        buffer[1] = volsOut[ sp.wValue&0xff ] >> 8;
                                        return XUD_DoGetRequest(ep0_out, ep0_in, buffer, 2,  sp.wLength);
                                    }
                                }
                                else
                                {
                                    if ((sp.wValue & 0xff) <= NUM_USB_CHAN_IN)
                                    {
                                        buffer[0] = volsIn[ sp.wValue&0xff ];
                                        buffer[1] = volsIn[ sp.wValue&0xff ] >> 8;
                                        return XUD_DoGetRequest(ep0_out, ep0_in, buffer, 2,  sp.wLength);
                                    }
                                }
                            }
                            
"else" subsection mean if we got FU_VOLUME_CONTROL event but command is not equal to USB_BM_REQTYPE_DIRECTION_H2D
I see audiorequest.xc file "Implements relevant requests from the USB Audio 2.0 Specification".

I would like to try sending some mystery "else" event (USB_BM_REQTYPE_DIRECTION_D2H seems to be) and see what Windows could do in this case. I also cannot get how to send this request to USB from other part of code, i.e. from my own code. It's really looks like a mess.
User avatar
Wavelength
Experienced Member
Posts: 76
Joined: Mon Sep 24, 2018 9:56 pm

Post by Wavelength »

Maxim,

No I didn't invent async, I did make it very popular. So here is what really happened. A large company made a USB DAC headphone amplifier (I have one of these) and Texas Instruments made them a USB capable DSP for this. The design originally was for adaptive but on some Windows machines the USB-DSP chip could not change the MCLK enough to keep synced with the host. The company had a already produced I guess a boat load of these. So TI and this other company went to USB.org and said we need a new protocol set that is async and requires feedback. It got adopted and I took it from there back in 2003 and moved it into audio.

~~~
That code looks like it would effect the feature unit on the host. It would be pretty easy to give it a try. Again you would want to test this on Windows and Linux (if you support it). If you have a Windows driver for Win7 & Win8 then trying it on them also would be beneficial.

Thanks,
Gordon
Wavelength Audio, ltd.
MaximLiadov
XCore Addict
Posts: 130
Joined: Mon Apr 16, 2018 9:14 am

Post by MaximLiadov »

Gordon, thank you for so detailed history excursion! Fantastic! Very interesting. Though some audiophilic people still claim "USB is not capable to provide any decent sound quality, unlike SPDIF".

Yes, I support any UAC2.0 OS, as these days it's very simple to do. http://xcore.com/viewtopic.php?p=34745#p34745 Extremely helpful topic with the latest descriptor bugfix. Everything works fine.

Hope, some day I could make device-to-host volume works. Seems to be I need to pass USB_BM_REQTYPE_DIRECTION_D2H to some pipeline to initiate OS volume change.
Last edited by MaximLiadov on Thu Feb 27, 2020 6:50 am, edited 1 time in total.
User avatar
Wavelength
Experienced Member
Posts: 76
Joined: Mon Sep 24, 2018 9:56 pm

Post by Wavelength »

Maxim,
SPDIF sucks as you always have to fix the jitter. It's so much easier to just do it right the first time. It does take a lot of work and analysis. I have a full lab setup with Tektronix USB analyzers and a couple of different protocol analyzers to help me out with this stuff.
I still have some boards with SPDIF BNC input at 44.1 only with really low jitter VCXO controlled by a real elaborate setup that runs the SPDIF receiver in slave mode and then reclocks with the same VCXO. I get good results with that but not as good as putting the oscillator at the dac chip then reclock everything from the XMOS with the output MCLK from the dac chip. I also rewrite the async routines to better the flow of data.
Thanks,
Gordon
Wavelength Audio, ltd.
Post Reply