TheKikGen / MPC-LiveXplore

Akai MPC Live/X/Force/One technical explorations and hacks
211 stars 22 forks source link

Any way to activate the USB-B port in Standalone mode? (MPC One) #55

Open PolyVector opened 9 months ago

PolyVector commented 9 months ago

I'm trying to enable the USB-B port while in Standalone mode so that I can run audio in/out of my Linux machine over a single usb cable. My goal is to work mostly on the MPC, but use an audio plugin I'm developing as an external synth. Hopefully someone more knowledgeable could point me in the right direction.

Digging in, it appears the "Gadget" port is being dynamically activated/deactivated with systemd services:

Enabling Controller mode: I see this in journalctl:

Sep 23 18:28:56 mpc-one kernel: dwc2 ff580000.usb: bound driver configfs-gadget

As expected there are additional devices in both systemctl and alsa:

root@mpc-one:/# systemctl list-units | grep "gadget"
  sys-devices-platform-ff580000.usb-gadget-sound-card2-controlC2.device                         loaded active plugged   /sys/devices/platform/ff580000.usb/gadget/sound/card2/controlC2                        
  sys-devices-platform-ff580000.usb-gadget-sound-card3-controlC3.device                         loaded active plugged   /sys/devices/platform/ff580000.usb/gadget/sound/card3/controlC3                        
  usb-gadget.target                                                                             loaded active active    Hardware activated USB gadget                                                          
root@mpc-one:/# aplay -l
**** List of PLAYBACK Hardware Devices ****
card 1: ACVA [ACVA], device 0: ACVA PCM inmusic,acva-audio-codec-0 [ACVA PCM inmusic,acva-audio-codec-0]
  Subdevices: 0/1
  Subdevice #0: subdevice #0
card 2: UAC2Gadget [UAC2_Gadget], device 0: UAC2 PCM [UAC2 PCM]
  Subdevices: 0/1
  Subdevice #0: subdevice #0

Enabling Standalone mode: I see this in journalctl:

`Sep 23 18:40:06 mpc-one az01-launch-MPC[1330]: Gadget state changed: disconnected`

And sadly the additional devices are gone from systemctl and alsa:

root@mpc-one:/# systemctl list-units | grep "gadget"
  usb-gadget.target 
root@mpc-one:/# aplay -l
**** List of PLAYBACK Hardware Devices ****
card 1: ACVA [ACVA], device 0: ACVA PCM inmusic,acva-audio-codec-0 [ACVA PCM inmusic,acva-audio-codec-0]
  Subdevices: 0/1
  Subdevice #0: subdevice #0

I feel like there must be a way to turn the port back on with systemd or udevadm, but I'm not sure where to start.

TheKikGen commented 9 months ago

In controller mode, your MPC becomes a sound card. It seems not possible to use that USB B port to communicate with a plugin , as you'll need the MPC host app. The best way could be to communicate via Alsa e.g. allocate 2 virtual channels to your plugin. You need to modify the Alsa conf. Not easy but possible. I investigated a little on that : I wanted to use the internal channels + my 24 channels digital mixer, and stack all that...

PolyVector commented 9 months ago

Thanks for the info, I saw the main mpc service/app appears to manage all the hardware binding and alsa stuff. I'll probably continue digging around in my spare time to see what's possible. Good idea adding alsa virtual channels. I'll post here if I get anything usable.

PolyVector commented 9 months ago

After digging around in the kernel documentation and pretending to understand any of it, I've made some actual progress! I have USB-B MIDI fully working, and Audio is almost there...

Simply run this script when the MPC is in Standalone mode, and the USB-B Gadget device will be bound and configured. New MIDI in/out ports will show up and work perfectly, but the Audio ports will fail if used. On the PC side I'm using Linux+Pipewire so I just wire everything up with Helvum and I'm good to go.

If we can get the Audio working this could make a nice module. Cheers!

Updated script to fix audio:

#!/bin/sh

######################################################################
# This script enables MPC One USB-B port MIDI/Audio Gadget (Interface)
######################################################################

###################################################################################
#   KNOWN ISSUES:
#       1)  Using MIDI+Audio can cause the driver to go into a funk eating up CPU:
#           When this happens, the MPC will report 100% cpu and garble the playback
#           Output of "top" on the MPC when this happens:
#               110     2 root     RW       0   0%  16% [irq/74-ff580000]
#       2)  Using Audio requires BOTH Input and Output to be used by your PC
#           Otherwise the MPC will complain and switch the Audio Device
#           This is likely due to audio buffers filling up or emptying completely
###################################################################################

# Optional Settings:
# Akai Default: 3
MIDI_PORT_COUNT=1

# Globals:
CONFIGFS_HOME=/sys/kernel/config
GADGET_NAME="smexstream"
SERIAL_NUMBER=$(fw_printenv -n 'serial#')

stage () {
    # Helpful for debugging where things go wrong...
    echo "=== $1 ==="
}

# Not sure if this is needed...
modprobe libcomposite

stage Create a new Config
mkdir "$CONFIGFS_HOME/usb_gadget/$GADGET_NAME"
cd "$CONFIGFS_HOME/usb_gadget/$GADGET_NAME"

stage Identifiers
echo "0x0101" > "bcdDevice"
echo "0x0200" > "bcdUSB"
echo "0x00" > "bDeviceClass"
echo "0x00" > "bDeviceProtocol"
echo "0x00" > "bDeviceSubClass"
echo "0x40" > "bMaxPacketSize0"
echo "0x1046" > "idProduct"
echo "0x09e8" > "idVendor"
echo "super-speed-plus" > "max_speed"

stage Place to store Strings
mkdir strings/0x409

stage Basic Info
echo "$SERIAL_NUMBER" > "strings/0x409/serialnumber"
echo "Akai Professional" > "strings/0x409/manufacturer"
echo "MPC One" > "strings/0x409/product"

stage Strings
mkdir configs/config.1

stage Attributes
echo "2" > configs/config.1/MaxPower
echo "0xc0" > configs/config.1/bmAttributes

stage Functions
#mkdir functions/ffs.smexstream

# stage Mass Storage
# mkdir functions/mass_storage.block
# cd functions/mass_storage.block
#     echo "0" > "stall"
#     #mkdir "lun.0"
#     echo "0" > "lun.0/cdrom"
#     echo "" > "lun.0/file"
#     echo "" > "lun.0/inquiry_string"
#     echo "0" > "lun.0/nofua"
#     echo "1" > "lun.0/removable"
#     echo "0" > "lun.0/ro"
# cd ../..

stage UAC2
mkdir functions/uac2.audio
cd functions/uac2.audio
    echo "3" > "c_chmask"
    echo "0" > "c_mute_present"
    echo "44100" > "c_srate"
    echo "4" > "c_ssize"
    echo "async" > "c_sync"
    echo "0" > "c_volume_max"
    echo "-25600" > "c_volume_min"
    echo "0" > "c_volume_present"
    echo "256" > "c_volume_res"
    echo "0" > "explicit_feedback"
    echo "50" > "fb_max"
    echo "2" > "hs_interval"
    echo "1" > "named_channels"
    echo "3" > "p_chmask"
    echo "0" > "p_mute_present"
    echo "44100" > "p_srate"
    echo "4" > "p_ssize"
    echo "0" > "p_volume_max"
    echo "-25600" > "p_volume_min"
    echo "0" > "p_volume_present"
    echo "256" > "p_volume_res"
    echo "6" > "req_number"
    echo "1" > "shared_clock"

    mkdir strings/0x0409
    echo "MPC One Audio" > "strings/0x0409/association"
    echo "MPC One Audio" > "strings/0x0409/audio_in"
    echo "MPC One Audio" > "strings/0x0409/audio_out"
    echo "MPC One Audio" > "strings/0x0409/control"
cd ../..

if [ "$MIDI_PORT_COUNT" -gt "0" ]; then
    stage MIDI
    mkdir functions/midi.midi
    cd functions/midi.midi
        echo "512" > "buflen"
        echo "MPC One MIDI" > "id"
        # ERROR: Invalid argument (-1)
        #echo "-1" > "index"
        echo "$MIDI_PORT_COUNT" > "in_ports"
        echo "$MIDI_PORT_COUNT" > "out_ports"
        echo "32" > "qlen"

        mkdir strings/0x0409
        echo "MPC One MIDI" > "strings/0x0409/interface"
    cd ../..
fi

stage Associate Functions with Config
#ln -s functions/ffs.smexstream configs/config.1
#ln -s functions/mass_storage.block configs/config.1
ln -s functions/uac2.audio configs/config.1
if [ "$MIDI_PORT_COUNT" -gt "0" ]; then
    ln -s functions/midi.midi configs/config.1
fi

stage OS Desc???
#mkdir "os_desc" # Already exists
echo "0x10" > os_desc/b_vendor_code
echo "MSFT100" > os_desc/qw_sign
echo "1" > os_desc/use

stage Link OS Desc with Config
#ln -s configs/config.1 os_desc

stage Enable

# Taken from /sys/class/udc/
# sh: write error: No such device...
# This can mean that the device is used by another driver (SD Card? Something else?)
echo "ff580000.usb" > UDC

# WIP script for disabling the gadget below:
exit 0 ##################################################################################################

stage Disable Gadget
echo "" > UDC

stage Remove Functions in Config
#rm configs/config.1/functions/ffs.smexstream
#rm configs/config.1/functions/mass_storage.block
rm configs/config.1/functions/uac2.audio
if [ "$MIDI_PORT_COUNT" -gt "0" ]; then
    rm configs/config.1/functions/midi.midi
fi

stage Remove Strings from Config
rmdir configs/config.1/strings/0x409

stage Remove Config
rmdir configs/config.1

stage Remove Functions
#rmdir functions/ffs.smexstream
#rmdir functions/mass_storage.block
rmdir functions/uac2.audio
if [ "$MIDI_PORT_COUNT" -gt "0" ]; then
    rmdir functions/midi.midi
fi

stage Remove Strings
rmdir strings/0x409

stage Remove Gadget
cd ..
rmdir "$GADGET_NAME"

Edit: Here's a quick script that can reset the Gadget in the event it gets itself into a funk:

#!/bin/sh

MUX_DIR=/sys/devices/platform/usb-otg-mux
echo "host" > "$MUX_DIR/state"
sleep 1
echo "peripheral" > "$MUX_DIR/state"
PolyVector commented 9 months ago

Alright, I've updated the above script to fix audio, but there are some caveats mentioned in the comments..

The biggest issue is that using MIDI and Audio simultaneously can cause the MPC to eat CPU and garble audio. Edit: This hasn't been an issue for me, it may have been a bug with an older version of pipewire? Edit: The issue came back, it seems to depend on what combinations of input/output/midi ports are used on a particular song... Might be some kind of infinite feedback issue... top shows the irq eating CPU when this happens:

109     2 root     RW       0   0%  15% [irq/74-ff580000]

A less annoying issue is that if you use the Gadget Audio interface, you must use both Input and Output streams, or the MPC will get mad and switch your interface back. On Linux+Pipewire this meant routing the MPC to my speakers and a microphone to the MPC. On other platforms, this may look different.

If you don't plan on using MIDI, I would recommend setting MIDI_PORT_COUNT=0 to avoid accidentally tripping up the driver.

Hopefully this will be helpful to someone! :)

estufilla commented 4 months ago

Hi! Avid reader here lately, I would like to ask some questions if you don't mind.

First of all, just give huge thank you to both of you for your huge work for us MPC users. Just amazing.

Before any question just point out that I have like -10 experience in any of this, so probably will be quite "stupid" questions. (first approach to Linux was literally 2 months ago that I chrooted a Debian in my Android device, and 2 weeks ago I woke up one day and said "no more Windows!", so I'm here sitting in my PC with Arch (Manjaro) and truly enjoying it).

So, I got my MPC One ssh'ed, and the first thing that I tried was your USB Audio script (PolyVector). Works flawlesly, and as you pointed out, just easy to setup with PW/RaySessions/Carla.

Now, the question I always had is... There are USB mixers (aka Tascam Model 12), that you just plug-in to any MPC and works out of the box (tested). You just have your mixer with split channels as you are supposed to. So, if this mixer (and prob many more), are capable of just getting all the channels of the MPC, why or how could we do it directly to a for ex a Linux system? Isn't there any way to just make source/sinks in the alsa MPC as you could do in any Linux environment?

Apart from that... a question for myself, or rather for "the good of my MPC". I understand that I'm touching here things I shouldn't be, and specially with the lack of knowledge I do have right now on any Linux related thing, still, is there any way I can hard-brick the MPC if I just "poke-and-try"? If so, is there after a way to restore a firmware like an Android device with ADB/Fastboot etc?

Sorry for my seriously basic questions, just thought this post with you two here could give me some huge answers. Apologies for the de-rail.

Thank you.

Fran.

PolyVector commented 4 months ago

Glad someone found the script useful, I've had a lot of fun with it :)

Regarding the usb mixer, I assume your goal is to hook it up to your computer, and have the channels in Pipewire/etc route to the MPC. This is probably possible, and I think you'd have to edit the "UAC2" portion of the script to create additional sinks/sources, but that's beyond my current skills unfortunately...

As for potentially bricking it, I'll let someone more knowledgeable answer that, but I will say I haven't had an issue. It helps that the main OS is installed as read-only.

estufilla commented 4 months ago

Sooo, let's learn then. I've been actually poking around half afternoon to see what can I find, but not much honestly. I was thinking tho, as TheKikGen pointed out, when using the MPC in controller mode, the MPC becomes a "soundcard". We're using USB-B here, but when you use an audio interface on the MPC (interface, usb mixer...), for ex the Tascam Model 12 I mentioned earlier, you use it on the USB-A. Could it be that only the channels could get out only in the USB-A? I understand nothing about bauds and such, but I think I read somewhere that only fast USB 2.0+ can carry the "44 channels".

Either way, just saw you edited your other post and mentioned about no problem on the midi+audio side, so I'm on it right now!

PolyVector commented 4 months ago

I misunderstood what you wanted, but I see now you want to connect the USB mixer to the MPC. I think the main thing restricting you is simply the MPC software, which only is designed to select one interface at a time. Maybe you could look into creating some virtual interface that bridges the USB mixer and the UAC2 device into a single larger device? I wouldn't even know where to begin on that, heh :)

estufilla commented 4 months ago

Oh no, you actually got it right before, sorry to mislead you now. I mention the Tascam just as an example.

What I want to do is basically use a "computer" (or any other capable device ofc), as an audio interface. For example in this case, if I have lets say, 2 tracks, 1 with Kick plugin and 2 with Hats plugin (to say something), have those 2 tracks sent on separate audio channels (1/2, 3/4... etc).

I was just thinking about the UAC2, and with all my ignorance I just think this can't be done. Maybe could be done with the main soundcard (which is the one used for audio interfaces I think), not the UAC2 which is only and explicitly made to just make a loopback with the MPC software, so only 1 stereo in and 1 stereo out.

So, recap here: There's 2 soundcards in the MPC (MPC One at least). One is used in general use, for audio interfaces (which the option in audio settings "32 in out" would be for this use), and the other one which is made for the MPC software purpose.

Is it like this or am I just making a movie in my head?

And btw, sorry if I ramble, english is not my main language and not something we got taught here in Spain xD

PolyVector commented 4 months ago

Ah okay, I misread (I'm currently distracted)

What I want to do is basically use a "computer" (or any other capable device ofc), as an audio interface. For example in this case, if I have lets say, 2 tracks, 1 with Kick plugin and 2 with Hats plugin (to say something), have those 2 tracks sent on separate audio channels (1/2, 3/4... etc).

This should certainly be possible with UAC2 if you are able to add additional channels to my script, I just don't know how to do that. UAC2 (as I understand it) is a standard that can support many inputs/outputs, and it's even likely that your USB mixer is a UAC2 device. As for how the MPC One's software would handle additional channels, you'd have to try and see.

So, recap here: There's 2 soundcards in the MPC (MPC One at least). One is used in general use, for audio interfaces (which the option in audio settings "32 in out" would be for this use), and the other one which is made for the MPC software purpose.

I think you're right in your assessment. The main difference between the 2 interfaces, is the UAC2 (USB-B) device is acting like a device you hook up to a host/computer, and not the host/computer itself.

estufilla commented 4 months ago

Well, yes. Now that you say it, makes absolute sense to be able to do it with UAC2 or any other available, so to learn I'm headed. Thank you!

estufilla commented 1 month ago

Guys! Long time no see!

Sorry I ended up breaking an IC of the screen by mistake and didn't touch the thing anymore.

BUT! I did have a crazy thought right now. So I have another device (uConsole) which runs on a CM4 (RPI4B basically). Could this thing entirely be ran in the CM4 providing the kernel (which I can build)? I mean, the MPC it's a RK3288, which is not really far from it. There's even a uConsole model with the RK3288.