Difference between revisions of "Audio Through USB"

From MOD Wiki
Jump to navigation Jump to search
Line 80: Line 80:
 
'''NOTE: This is EXPERIMENTAL and doesn't work on Windows right now.'''
 
'''NOTE: This is EXPERIMENTAL and doesn't work on Windows right now.'''
  
 
We are going to enable USB Audio Gadget as UAC2 by replacing some system files and activating the unit gadget mode.
 
  
 
First [[Access_MOD_using_SSH|ssh into the unit]], and run:
 
First [[Access_MOD_using_SSH|ssh into the unit]], and run:
Line 87: Line 85:
 
<source lang="bash">
 
<source lang="bash">
 
touch /data/enable-usb-multi-gadget
 
touch /data/enable-usb-multi-gadget
mount / -o remount,rw
+
touch /data/enable-usb-audio-gadget
</source>
+
# if using windows, also run:
 
+
touch /data/enable-usb-windows-compat
Second, open /sbin/enable-usb-gadget.sh inside the unit (with either nano or vi, as you prefer) and replace its entire contents with:
 
<source lang="bash">
 
#!/bin/bash
 
 
 
source /etc/mod-hardware-descriptor.env
 
 
 
# If we need to wait for usb to be plugged in before activating gadget mode, do nothing
 
# On such units, we can only register g_ether after the USB is plugged in
 
if [ "${USB_PLUGGED_IN_WAIT_REQUITED}" -eq 1 ] && [ -n "${STARTED_VIA_SYSTEMD}" ]; then
 
    exit 0
 
fi
 
 
 
if [ -f /data/enable-usb-multi-gadget ] && [ -e /proc/device-tree/compatible ]; then
 
    /sbin/modprobe libcomposite
 
 
 
    if [ -f /data/enable-usb-windows-compat ]; then
 
        /sbin/modprobe usb_f_rndis
 
        WINDOWS_COMPAT_MODE=1
 
    else
 
        WINDOWS_COMPAT_MODE=0
 
    fi
 
 
 
    # Read serial
 
    if [ -f /var/cache/mod/tag ]; then
 
        SERIAL=$(cat /var/cache/mod/tag)
 
    else
 
        SERIAL=$(mod-hardware tag)
 
    fi
 
    SERIAL=$(echo ${SERIAL} | awk 'sub("-","\n")' | tail -n 1 | sed 's/-//g')
 
 
 
    # Create MAC address suffix
 
    MAC=$(echo ${SERIAL} | tail -c 10 | sed 's/\(\w\w\)/:\1/g')
 
 
 
    # create new composite gadget instance
 
    mkdir /sys/kernel/config/usb_gadget/multi
 
    cd /sys/kernel/config/usb_gadget/multi
 
 
 
    # assign an unique id based on model, so each one is handled separately/differently by the host OS
 
    if [ "${PLATFORM}" = "duo" ]; then
 
        PRODUCT_CODE="1"
 
    elif [ "${PLATFORM}" = "dwarf" ]; then
 
        PRODUCT_CODE="2"
 
    elif [ -n "${MODEL_IMX8MQ}" ] && [ "${MODEL_IMX8MQ}" -eq 1 ]; then
 
        PRODUCT_CODE="3"
 
    else
 
        PRODUCT_CODE="4"
 
    fi
 
 
 
    # please increment this value everytime you make changes here!
 
    PRODUCT_VERSION="1"
 
 
 
    # make a unique device id based on previous values
 
    echo "0x3${PRODUCT_CODE}${PRODUCT_VERSION}${WINDOWS_COMPAT_MODE}" > bcdDevice
 
 
 
    # USB ID, see more at http://www.linux-usb.org/usb.ids
 
    echo "0x1d6b" > idVendor
 
    echo "0x0104" > idProduct
 
 
 
    # Setup USB Gadget
 
    echo 0x0200 > bcdUSB # USB 2.0
 
    echo 0xEF > bDeviceClass # Miscellaneous
 
    echo 0x02 > bDeviceSubClass
 
    echo 0x01 > bDeviceProtocol
 
 
 
    # USB Information (0x409 is English)
 
    mkdir strings/0x409
 
    echo "MOD Devices" > strings/0x409/manufacturer
 
    echo "${MODEL_NAME}" > strings/0x409/product
 
    echo "${SERIAL}" > strings/0x409/serialnumber
 
 
 
    # Setup MIDI
 
    mkdir functions/midi.usb0
 
 
 
    if [ ${WINDOWS_COMPAT_MODE} -eq 1 ]; then
 
        # Setup RNDIS
 
        mkdir functions/rndis.usb0
 
        echo "22${MAC}" > functions/rndis.usb0/dev_addr
 
        echo "32${MAC}" > functions/rndis.usb0/host_addr
 
        echo "RNDIS" > functions/rndis.usb0/os_desc/interface.rndis/compatible_id
 
        echo "5162001" > functions/rndis.usb0/os_desc/interface.rndis/sub_compatible_id
 
 
 
        ## Hacky stuff for Windows
 
        echo "1" > os_desc/use
 
        echo "0xcd" > os_desc/b_vendor_code
 
        echo "MSFT100" > os_desc/qw_sign
 
    else
 
        # Setup ECM
 
        mkdir functions/ecm.usb0
 
        echo "02${MAC}" > functions/ecm.usb0/dev_addr
 
        echo "12${MAC}" > functions/ecm.usb0/host_addr
 
 
 
        # Setup UAC2
 
        mkdir functions/uac2.usb0
 
        echo "3" > functions/uac2.usb0/c_chmask
 
        echo "3" > functions/uac2.usb0/c_ssize
 
        echo "48000" > functions/uac2.usb0/c_srate
 
        echo "3" > functions/uac2.usb0/p_chmask
 
        echo "3" > functions/uac2.usb0/p_ssize
 
        echo "48000" > functions/uac2.usb0/p_srate
 
    fi
 
 
 
    # Configuration
 
    mkdir configs/mod.1
 
    echo "0xc0" > configs/mod.1/bmAttributes # self-powerered
 
    echo "1" > configs/mod.1/MaxPower # 2mA
 
 
 
    mkdir configs/mod.1/strings/0x409
 
    echo "${MODEL_NAME}" > configs/mod.1/strings/0x409/configuration
 
 
 
    if [ ${WINDOWS_COMPAT_MODE} -eq 1 ]; then
 
        ln -s functions/rndis.usb0 configs/mod.1
 
        ln -s configs/mod.1 os_desc
 
    else
 
        ln -s functions/ecm.usb0 configs/mod.1
 
        ln -s functions/uac2.usb0 configs/mod.1
 
    fi
 
 
 
    ln -s functions/midi.usb0 configs/mod.1
 
 
 
    # Ready to roll!
 
    /bin/find /sys/class/udc -type l -maxdepth 1 | /bin/tail -n 1 | /bin/awk 'sub("/sys/class/udc/","")' > UDC
 
else
 
    /sbin/modprobe g_ether
 
fi
 
 
 
# Setup IRQ priority, taken from `set-irq-priorities.sh`
 
if [ -n "${USB_IRQ}" ]; then
 
    USB_PID=$(/usr/bin/ps -e | /usr/bin/grep irq/${USB_IRQ} | /usr/bin/awk '{print $1}')
 
    # USB IRQ is sometimes only active if a usb host or gadget is plugged in
 
    if [ -n "${USB_PID}" ]; then
 
        # we can have 2 processes handling usb
 
        if [ "$(/usr/bin/echo ${USB_PID} | /usr/bin/wc -w)" -eq 2 ]; then
 
            USB_PIDS=($(/usr/bin/echo ${USB_PID}))
 
            /usr/bin/chrt -f -p 55 ${USB_PIDS[0]}
 
            /usr/bin/chrt -f -p 55 ${USB_PIDS[1]}
 
        else
 
            /usr/bin/chrt -f -p 55 ${USB_PID}
 
        fi
 
    fi
 
fi
 
 
 
# Bring up usb0 ethernet interface
 
/sbin/ifup usb0
 
 
 
# Restarts sshd service, needed after usb0 being active
 
/usr/bin/systemctl restart sshd
 
 
 
# On legacy units, g_ether waits for first USB to be plugged in
 
# As such, netmanager cannot start on boot, so do that now
 
if [ -f /data/enable-netmanager ] && [ "${USB_PLUGGED_IN_WAIT_REQUITED}" -eq 1 ]; then
 
    /usr/bin/systemctl start jack-netmanager
 
fi
 
 
 
exit 0
 
 
</source>
 
</source>
  
 
Now we reboot
 
Now we reboot
 
<source lang="bash">
 
<source lang="bash">
 +
sync
 
hmi-reset
 
hmi-reset
sync
 
 
reboot
 
reboot
 
</source>
 
</source>
  
The UAC2 mode is now active. Once a unit is booted up again, simply activate extra audio inputs with:
+
Some caveats and known issues:
 
 
<source lang="bash">
 
jack_load mod-slave zita-a2j -i "-d hw:UAC2Gadget -p 128 -n 4"
 
</source>
 
 
 
If something fails, boot into restore mode and reinstall to start fresh.
 
  
This will be part of an official MOD release at some point, these contents are written here in the hopes of being useful, but it is really only meant for advanced users for now.
+
* USB audio requires very precise timings, loading big resources on the web interface over USB can lead to audio dropouts (the best results are with web interface loaded over WiFi, leaving USB for audio and MIDI)
 +
* De-sync of USB packets will pause the audio (either capture or playback) for 10 seconds
 +
* Not supported on Windows right now, to be dealt with later on
 +
* MOD Duo works 100%
 +
* MOD Duo X limited-edition works in playback-only mode
 +
* MOD Duo X works well most of the time, with occasional playback sync issues
 +
* MOD Dwarf has issues with playback, but capture works well

Revision as of 04:11, 14 February 2021

Using netJACK2

NOTE: This requires v1.4 or later.

First, connect the MOD Duo to your PC via usb cable. Make sure to open port 19000 on your firewall. If you use Linux with ufw, you can use:

sudo ufw allow 19000

Then, ssh into the Duo, and run:

touch /data/enable-netmanager
systemctl start jack-netmanager

NOTE: You only need to run this command once. The next the Duo boots, jack-netmanager will be loaded by default. Delete the /data/enable-netmanager file inside the Duo to remove this auto-start feature.

Now run jackd on your own computer (connected to the Duo via USB), like this:

jackd -R -P 80 -d net -a 192.168.51.1 -C 2 -P 2 -i 1 -o 1 -l 4 -n mod-slave -s

Adjust the parameters as needed, but keep mod-slave as the client name.

Parameters explained

-R Use realtime scheduling, enabled by default.
-P Set the realtime scheduling priority, in this case 80.
-d JACK backend, in this case the "net" driver.
-a Multicast address, in this case the IP address of the MOD Duo.
-C Number of audio input ports on the slave. This determines the number of audio output ports on the MOD Duo, marked as "Hardware Audio To Slave" ports in the web interface.
-P Number of audio output ports on the slave. This determines the number of audio input ports on the MOD Duo, marked as "Hardware Audio From Slave" ports in the web interface.
-i Number of MIDI input ports on the slave. This determines the number of MIDI output ports on the MOD Duo, marked as "Hardware Midi To Slave" ports in the web interface.
-o Number of MIDI output ports on the slave. This determines the number of MIDI input ports on the MOD Duo, marked as "Hardware Midi From Slave" ports in the web interface.
-l Number of cycles, determines the network latency.
-s Setting this option makes the JACK slave memorize the ports that are connected to the JACK master. In case the master disappears and reappears the JACK slave will try to reconnect those ports automatically.

or if you prefer to use jackdbus:

jack_control eps realtime true eps realtime-priority 80
jack_control ds net dps multicast-ip 192.168.51.1 dps client-name mod-slave
jack_control dps input-ports 2
jack_control dps output-ports 2
jack_control dps midi-in-ports 1
jack_control dps midi-out-ports 1
jack_control dps latency 4
jack_control dps auto-save true
jack_control start

Using USB Audio Gadget

NOTE: This requires v1.10 or later.

NOTE: This is EXPERIMENTAL and doesn't work on Windows right now.


First ssh into the unit, and run:

touch /data/enable-usb-multi-gadget
touch /data/enable-usb-audio-gadget
# if using windows, also run:
touch /data/enable-usb-windows-compat

Now we reboot

sync
hmi-reset
reboot

Some caveats and known issues:

  • USB audio requires very precise timings, loading big resources on the web interface over USB can lead to audio dropouts (the best results are with web interface loaded over WiFi, leaving USB for audio and MIDI)
  • De-sync of USB packets will pause the audio (either capture or playback) for 10 seconds
  • Not supported on Windows right now, to be dealt with later on
  • MOD Duo works 100%
  • MOD Duo X limited-edition works in playback-only mode
  • MOD Duo X works well most of the time, with occasional playback sync issues
  • MOD Dwarf has issues with playback, but capture works well