6 channel line level audio interface with teensy 4.1?

Well, bad news for me, but potentially good news for those looking to further teensy audio: my interfaces can't be aggregated because they can only use internal clock sources. So back to this plan! Haha
 
Now trying to get a little more detailed in my prep for this, I'm realizing each audio board needs power, and it doesn't look like they can pull from the USB bus power of the teensy? Would be nice if it all could be USB powered but if not it is what it is.
 
Shouldn't be an issue to run at least a couple of audio boards from a Teensy 4.1 - the website says you can take 250mA off the 3.3V, and the audio boards are way less than that.

I've been trying to sort out the glitches, and have made some progress, specifically USB output (Teensy to host) seems much improved. At this point making use of it is a bit of a bear, as it needs modifications in multiple places:
  • cores/teensy4 - see this repo: I think you only need usb.c, usb_audio.cpp and .h, and usb_desc.c and .h
  • Audio - see this repo: just gui/index.html to allow you to place different width USB I/O, and keywords.txt so they highlight in the Arduino IDE
  • changes to IDE configuration files:
platform.txt - add the items shown here in red - scroll down, make sure you don't miss anything:
Code:
name=Teensyduino
version=1.8.5
rewriting=disabled

# Teensyduino Installer
compiler.path={runtime.hardware.path}/../tools/
teensytools.path={runtime.hardware.path}/../tools/

# Arduino Boards Manager
#compiler.path={runtime.tools.teensy-compile.path}/
#teensytools.path={runtime.tools.teensy-tools.path}/

[COLOR="#FF0000"]build.flags.audioblocksize=128
build.flags.audiorate=44100.0f
build.flags.USBchannelcount=2

build.flags.audio=-DAUDIO_BLOCK_SAMPLES={build.flags.audioblocksize} -DAUDIO_SAMPLE_RATE_EXACT={build.flags.audiorate} -DAUDIO_USB_CHANNEL_COUNT={build.flags.USBchannelcount}[/COLOR]

## EEPROM Data
compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0
compiler.elf2hex.flags=-O ihex -R .eeprom

## Preprocessor Includes
recipe.preproc.includes="{compiler.path}{build.toolchain}{build.command.g++}" -M -MG -MP -x c++ -w {build.flags.cpp} {build.flags.cpu} {build.flags.defs} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DF_CPU={build.fcpu} -D{build.usbtype} -DLAYOUT_{build.keylayout} {includes} "{source_file}"

## Preprocessor Macros
recipe.preproc.macros="{compiler.path}{build.toolchain}{build.command.g++}" -E -CC -x c++ -w {compiler.cpp.flags} {build.flags.common} {build.flags.cpp} {build.flags.cpu} {build.flags.defs} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DF_CPU={build.fcpu} -D{build.usbtype} -DLAYOUT_{build.keylayout} {includes} "{source_file}" -o "{preprocessed_file_path}"

## New Preprocessor for Arduino 1.9
tools.arduino-preprocessor.path={runtime.tools.arduino-preprocessor.path}
tools.arduino-preprocessor.cmd.path={path}/arduino-preprocessor
tools.arduino-preprocessor.pattern="{cmd.path}" "{source_file}" "{codecomplete}" -- -std=gnu++14

## Precompile Arduino.h header
recipe.hooks.sketch.prebuild.1.pattern="{teensytools.path}precompile_helper" "{runtime.platform.path}/cores/{build.core}" "{build.path}" "{compiler.path}{build.toolchain}{build.command.g++}" -x c++-header {build.flags.optimize} {build.flags.common} {build.flags.dep} {build.flags.cpp} {build.flags.cpu} {build.flags.defs} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DF_CPU={build.fcpu} -D{build.usbtype} -DLAYOUT_{build.keylayout} "-I{runtime.platform.path}/cores/{build.core}" "{build.path}/pch/Arduino.h" -o "{build.path}/pch/Arduino.h.gch"

## Compile c++ files
recipe.cpp.o.pattern="{compiler.path}{build.toolchain}{build.command.g++}" -c [COLOR="#FF0000"]{build.flags.audio}[/COLOR] {build.flags.optimize} {build.flags.common} {build.flags.dep} {build.flags.cpp} {build.flags.cpu} {build.flags.defs} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DF_CPU={build.fcpu} -D{build.usbtype} -DLAYOUT_{build.keylayout} "-I{build.path}/pch" {includes} "{source_file}" -o "{object_file}"

## Compile c files
recipe.c.o.pattern="{compiler.path}{build.toolchain}{build.command.gcc}" -c [COLOR="#FF0000"]{build.flags.audio}[/COLOR] {build.flags.optimize} {build.flags.common} {build.flags.dep} {build.flags.c} {build.flags.cpu} {build.flags.defs} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DF_CPU={build.fcpu} -D{build.usbtype} -DLAYOUT_{build.keylayout} {includes} "{source_file}" -o "{object_file}"

## Compile S files
recipe.S.o.pattern="{compiler.path}{build.toolchain}{build.command.gcc}" -c [COLOR="#FF0000"]{build.flags.audio}[/COLOR] {build.flags.optimize} {build.flags.common} {build.flags.dep} {build.flags.S} {build.flags.cpu} {build.flags.defs} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DF_CPU={build.fcpu} -D{build.usbtype} -DLAYOUT_{build.keylayout} {includes} "{source_file}" -o "{object_file}"

## Create archives
recipe.ar.pattern="{compiler.path}{build.toolchain}{build.command.ar}" rcs "{archive_file_path}" "{object_file}"

Edit or add boards.local.txt
Code:
## Audio
# Extra menu entries to tune the behaviour of the Audio library

menu.audiorate=Audio sample rate
teensy41.menu.audiorate.44=44.1kHz
teensy41.menu.audiorate.44.build.flags.audiorate=44100.0f
teensy41.menu.audiorate.48=48kHz
teensy41.menu.audiorate.48.build.flags.audiorate=48000.0f
teensy41.menu.audiorate.96=96kHz
teensy41.menu.audiorate.96.build.flags.audiorate=96000.0f
teensy40.menu.audiorate.44=44.1kHz
teensy40.menu.audiorate.44.build.flags.audiorate=44100.0f
teensy40.menu.audiorate.48=48kHz
teensy40.menu.audiorate.48.build.flags.audiorate=48000.0f
teensy40.menu.audiorate.96=96kHz
teensy40.menu.audiorate.96.build.flags.audiorate=96000.0f

menu.audioblocksize=Audio block size
teensy41.menu.audioblocksize.normal=128 samples (normal)
teensy41.menu.audioblocksize.normal.build.flags.audioblocksize=128
teensy41.menu.audioblocksize.16=16 samples
teensy41.menu.audioblocksize.16.build.flags.audioblocksize=16
teensy41.menu.audioblocksize.256=256 samples
teensy41.menu.audioblocksize.256.build.flags.audioblocksize=256
teensy40.menu.audioblocksize.normal=128 samples (normal)
teensy40.menu.audioblocksize.normal.build.flags.audioblocksize=128
teensy40.menu.audioblocksize.16=16 samples
teensy40.menu.audioblocksize.16.build.flags.audioblocksize=16
teensy40.menu.audioblocksize.256=256 samples
teensy40.menu.audioblocksize.256.build.flags.audioblocksize=256

menu.USBchannelcount=USB channels
teensy41.menu.USBchannelcount.2=2
teensy41.menu.USBchannelcount.2.build.flags.USBchannelcount=2
teensy41.menu.USBchannelcount.4=4
teensy41.menu.USBchannelcount.4.build.flags.USBchannelcount=4
teensy41.menu.USBchannelcount.6=6
teensy41.menu.USBchannelcount.6.build.flags.USBchannelcount=6
teensy41.menu.USBchannelcount.8=8
teensy41.menu.USBchannelcount.8.build.flags.USBchannelcount=8
teensy40.menu.USBchannelcount.2=2
teensy40.menu.USBchannelcount.2.build.flags.USBchannelcount=2
teensy40.menu.USBchannelcount.4=4
teensy40.menu.USBchannelcount.4.build.flags.USBchannelcount=4
teensy40.menu.USBchannelcount.6=6
teensy40.menu.USBchannelcount.6.build.flags.USBchannelcount=6
teensy40.menu.USBchannelcount.8=8
teensy40.menu.USBchannelcount.8.build.flags.USBchannelcount=8

It's highly advisable to make a portable installation (Google is your friend here...) of the Arduino IDE to try out these changes! If it all works, you should have extra menu items, thus:
2023-06-04 22_04_20-USBsyncTest _ Arduino 1.8.19.png
I'd advise against changing the audio block size, but the USB channels and sample rate have had a bit of a test.

Run the Design Tool from your local updated copy, which should allow you to place the wider USB I/O objects:
2023-06-04 22_07_56-Audio System Design Tool for Teensy Audio Library.png
If you place an N-wide object but only configure the IDE for USB to have <N USB channels, you'll get a compile-time error.
 
So I *just* realized the connectors already soldered are in fact audio connectors, they looked like power, and it wasn't very clear on the site tbh. So with that, those would probably be input 1-2, then 5-6 on the next board, then it looks like there's pins L R and ground for "line in" so I'm guessing those would be my 3-4?
 
Not sure which board you’re describing. The PJRC audio adaptor has only the headphone output connector soldered, which duplicates the waveforms on the two line outputs but with a floating “ground” (don’t actually ground this!). You have to add a connector to the 2x5 header to access the line in/out signals, 2 channels of each so 1+2 out and in on adaptor 1, 3+4 on adaptor 2 and so on.
 
Ah, I misunderstood between Paul talking about 2 I2C ports, and you mentioning "a couple" audio adapters, that I would only need 2, which led me to assume I could get more inputs than 2 from one (ie 4 from one, 2 from another). Now I see I'll need to stack 3 adapters with the one teensy. Quite the setup for 6 ins! Haha
 
And with that, that brings the rough total of this project beyond $80, and I'm still not even entirely positive I'll be able to capture 6 lines cleanly... Hmmmmm...
(Of course still beats $500 for an interface haha)
 
Ok well given the circumstances, it is worth the lower investment to *try* an entertainment level ADC from Amazon just to get 2 more analog ins into the spdif in on my interface, bringing the total to 6. I *don't* have high hopes for 1) it being compatible with a studio audio interface, and 2) it sounding very good, but that's what the return policy is for... You will hear from me one way or the other with a report. Haha
 
Oh, I'm sure it'd be well north of $80 ... you've not added in the cost of 12x differential amplifiers, or the connectors, or the enclosure, or the power supply! I think many people take on a project like this for the challenge and satisfaction, not because its going to be cheap and easy, or even guaranteed of an outcome.

Then again I imagine a decent ADC to S/PDIF box would be a significant fraction of that, too. You can't win, probably. Well, you can - just pick a suitable value for "win".
 
Just gotta say this is so cool to see
:D
Now it’s just a matter of getting it into the official release … it’s a pity adding things to the Tools menu is so convoluted. The actual code isn’t what I’d call finished, but bleeding-edge enthusiasts are encouraged to give it a try and report back.
 
I've made some improvements to the multi-channel USB which I pushed up just now. The feedback sync is now apparently working, but only on a USB 1.1 connection. There's something screwy going on with USB 2.0, but it doesn't show up immediately - the test I did just now ran for over 3.5 minutes before glitches started occurring every 2.5 seconds or so. I've left in a deliberate one-sample "click" when a buffer overrun happens (PC -> Teensy) - see usb_audio.cpp line 261 if you want to remove it. Teensy -> PC seems to be working OK.

Pushed a half-finished version because I won't have a chance to look at this for a few days, so it's an ideal opportunity to have a play and see if you can get it to work, or find any other issues. I've only tested on Windows 10 x64, so Linux and Mac tests would be a bonus.
 
I've made some improvements to the multi-channel USB which I pushed up just now. The feedback sync is now apparently working, but only on a USB 1.1 connection. There's something screwy going on with USB 2.0
I can tell you I will definitely look when I have a bit more time, sounds interesting to me.
 
Well, this time bad news for the progression of teensy audio (for now), but good news for me, and I'm properly shocked: the 2 Amazon dac/adc boxes I got actually work! Not only that, they seem to sound pretty damn good. So for the time being, my input/output needs are sorted. But hey, it looks like perhaps my question led to some more progress from others? I can hope so, and that it wasn't just a complete waste of time. *nervous sweats*
Thanks so much everyone for your input!
 
Good news. Do report which S/PDIF boxes worked for you, always useful to know.

Always good to be prompted to go back to stuff that kinda faded away. Even if it isn’t immediately useful for you, there’s plenty of folk out there would like the multi-channel USB working. So, not a waste of time at all.
 
I'm currently in my busy season at work but I will most definitely be testing this soon. Thanks for your effort, h4yn0nnym0u5e.
 
No worries, it’d be great to have some feedback on how it works for others. It may be OK on Linux, but my current thinking is the descriptor for high speed USB is not fully compatible with Windows UAC2 drivers, hence the imperfect (non-existent?) sync on AudioUSBinput. That’s going to need some serious spec reading to fix, plus fighting Windows’s enthusiasm for caching known devices so your changes don’t show up. Sigh.
 
These 2: (one dac and one ADC, I wanted both in one but couldn't find one)
https://a.co/d/6RqSvPp
https://a.co/d/byft3ep
Thanks for that. I’ve got some similar ones, and the ADC also claims it can do different sample rates … but I’ve not found a way to do that. It’d be interesting to do it, if possible, as I got to a point where I had S/PDIF as the audio clock master, which was quite fun, and possibly even useful as well…
 
Ya, I had an issue initially where the tempo was faster than it should've been in my test project, but it turned out the daw "automatically" set the sample rate to 44.1, once I manually set it to 48 it was fine, which I took to mean that ADC can only do 48? That's what I tend to use anyway so it worked out for me. And yes, I also had to set my interface to external clock, which then used the ADC as clock. Actually, I just set it that way to begin with, but I could try internal and see if the ADC would somehow sync itself to the interface (doubt it since that usually happens through the digital connection and its is an output)
 
That’s going to need some serious spec reading to fix,

I've looked at the USB descriptors before and can imagine the difficulty involved. It seems to me that knowledge in this subject is super rare, too.

plus fighting Windows’s enthusiasm for caching known devices so your changes don’t show up. Sigh.

Now that you mentioned it, you may be able to use the Unified Write Filter. You can lock windows to read only mode.

https://learn.microsoft.com/en-us/windows/iot-core/secure-your-device/unifiedwritefilter
https://learn.microsoft.com/en-us/windows-hardware/customize/enterprise/uwf-turnonuwf
 
I've made some improvements to the multi-channel USB which I pushed up just now. The feedback sync is now apparently working, but only on a USB 1.1 connection. There's something screwy going on with USB 2.0, but it doesn't show up immediately - the test I did just now ran for over 3.5 minutes before glitches started occurring every 2.5 seconds or so. I've left in a deliberate one-sample "click" when a buffer overrun happens (PC -> Teensy) - see usb_audio.cpp line 261 if you want to remove it. Teensy -> PC seems to be working OK.

I have a bit more time over the next few weeks. Is this the branch you need some testing on?
https://github.com/h4yn0nnym0u5e/Audio/tree/mcginty/feature/USB-extra-channels
 
That branch of the Audio library gives you the ability to place different widths of USB input and output object. You also need changes to the cores, from https://github.com/h4yn0nnym0u5e/cores/commits/mcginty/feature/integrate-01. I kept it in line with Paul’s cores updates for a while, then stopped when it was apparent mcginty wasn’t interested any longer, and I was about to go on a month’s holiday. So it’s a bit out of date….

I think it may (appear to) be working on Linux, however certainly on Windows 10 the sync code isn’t quite working, but the resulting glitches are only one sample and can be really hard to detect.

I did briefly come back to it and started attempting to update the descriptor to full UAC2, because that seems to be what Windows needs, but it’s not working right now and there’s other easier stuff I can progress.

If you give it a go, do let us know how you get on.
 
Back
Top