[PYTHON] Erstellen Sie einen Audio-Interface-Controller mit pyusb (1).

Ich mache Musikaktivitäten als Hobby [^ 1], aber seit ich angefangen habe, Musik auf dem Linux-Computer zu machen, den ich bei der Arbeit verwendet habe, als ich ursprünglich privat damit gespielt habe und zu Hause gearbeitet habe, ist Linux immer noch das wichtigste Es ist eine Produktionsumgebung von. Und obwohl es verschiedene Hürden gibt, unter Linux Musik zu machen [^ 2], besteht eines der Hauptprobleme darin, dass der Titel auch ** Audio-Interface-Optionen ** enthält. Nein, wie ich später erläutern werde, hat es sich in letzter Zeit erheblich verbessert, sodass es weniger problematisch wird.

Einfach ausgedrückt ist ein Audio-Interface ein Gerät, das durch Anschließen verschiedener Geräte rauscharm aufnehmen / wiedergeben kann. Es ist für die Musikproduktion fast unverzichtbar, aber natürlich ist die Linux-Marktgröße in der Musikproduktion schwierig. Es ist weit entfernt von der Größenordnung, die Wearmaker dazu motiviert, Treiber für Linux zu schreiben, daher können wir das nicht erwarten.

In den letzten Jahren hat jedoch die Anzahl der Geräte zugenommen, die ** USB Class-konform ** für USB-Audioklasse [^ 3] beanspruchen. Da sie Grundfunktionen mit Allzwecktreibern verwenden können, können sie daher auch unter Linux verwendet werden. Es ist wie geworden. [^ 4] Andererseits gibt es natürlich Grenzen für Allzwecktreiber [^ 5], und die für jedes Gerät spezifischen Funktionen können überhaupt nicht verwendet werden. Ich habe bisher Native Instrument Komplete Audio 6 verwendet, und es war auch mit einem Allzwecktreiber nicht unpraktisch, aber das kürzlich gekaufte Focusrite Scarlett 18i20-Audiointerface verfügt über viele Funktionen, die der Allzwecktreiber nicht unterstützen kann. Kann nur über die von Focusrite (Focusrite Control) bereitgestellte Software gesteuert werden.

Auf die Frage "Warum haben Sie so etwas gekauft?" ** "Weil ich von Anfang an vorhatte, einen Controller für Linux zu entwickeln" **, aber es scheint nur eine Quelle für technische Artikel zu sein, also werde ich es von nun an mehrmals tun. Ich werde die Erstellung eines Audio-Interface-Controllers mit Pyusb separat schreiben.

Bibliothek und Software zu verwenden

Wie oben erwähnt, gibt es keine Linux-Version des Treibers, um die ursprüngliche Funktion zu verwenden. Daher werden wir hier die Interaktion zwischen Scarlett 18i 20 und Focusrite Control unter Windows erfassen und analysieren.

Zuerst dachte ich, dass libusb alleine den Trick machen würde, aber ein kurzer Blick auf die Quelle des WinUSB-Backends von libusb scheint mit einigen Geräten nicht kompatibel zu sein, und das Scarlett 18i 20 scheint nicht kompatibel zu sein. Es ist. (Wenn Sie den folgenden Code ausführen, ohne usbdk zu verwenden, tritt ein Fehler auf.) Wenn Sie das usbdk-Backend verwenden, können Sie mit pyusb arbeiten, aber in einigen Fällen ** kann es das Betriebssystem betreffen und fallen ** Wenn Sie also nachahmen möchten, was Sie in dem Artikel tun, sind Sie auf eigenes Risiko.

Protokollanalyseverfahren

Wenn Sie es schreiben, ist es nur das, aber das ist ziemlich mühsam. Natürlich ist die Analyse des Protokolls mehr oder weniger mühsam, aber selbst wenn nichts unternommen wird, wird eine große Menge von Datenprotokollen ausgespuckt, wie in der folgenden Abbildung gezeigt.

scarlet1-1.png

Wie auch immer, die Kommunikation erfolgt mit einer enormen Frequenz, und selbst wenn Sie etwas mit Focusrite Control betreiben, fließt das Protokoll sofort. Wenn Sie sich jedoch diese große Menge an Kommunikation ansehen, können Sie sehen, dass dies ein guter Hinweis ist.

Zunächst gibt es einen Teil, der wie eine Seriennummer aussieht. Daher ist es wahrscheinlich, dass Scarlett anhand der Seriennummer beurteilt, ob sich die Steuerungssoftware in einem konsistenten Zustand befindet. Und ich mache mir Sorgen, dass die Steuerübertragung vom 272-Byte-Scarlett fast mit 0 gefüllt ist. Probieren Sie nach dem Anwenden der folgenden Filter verschiedene Operationen aus.

DataSize == 272 && HexString != /^011000000001[0-9A-Z]{4}0{264}/

Aufgrund von Versuch und Irrtum scheint diese große Menge an Protokollen für Audiodaten bestimmt zu sein, wahrscheinlich für die Monitoranzeige von Focusrite Control. Dies wird später verwendet, wenn Sie eine ähnliche Monitorfunktion erstellen möchten. Da dies jedoch in letzter Zeit nicht erforderlich ist, wird es mit dem folgenden Filter unterdrückt.

DataSize != 272 && HexString != /^2102000003001800011000000/ && DataSize != 0 && HexString != "A103000003001001" && HexString != "0100000000000000"

Wenn dieser Filter angewendet wird, wird die ursprünglich erforderliche Interrupt-Übertragung unterdrückt. Es ist jedoch erforderlich, einen Teil des Filters zu entfernen und zu überprüfen.

Unmittelbar nach dem Einschalten von Scarlett oder beim Ausführen des später beschriebenen Skripts kann eine große Menge an Kommunikation außer den oben genannten bestätigt werden. Was den Speicherauszug der Kommunikationsinhalte betrifft, handelt es sich wahrscheinlich um eine Einrichtungssequenz, die nach dem Status fragt. Wenn Sie ein Programm ausführen, das usbdk verwendet, können Sie dieselbe Kommunikation überprüfen

Kann erraten werden.

Einfache Statusabfrage

Nachdem Sie eine allgemeine Vorstellung vom Analysefluss haben, analysieren Sie zunächst die Scarlett-Statusabfrage und schreiben Sie den Statusabfrageprozess in Python. Der ursprüngliche Zweck besteht darin, unter Linux zu arbeiten. Da ich den Code jedoch durch Ausprobieren schreibe, während ich den regulären Kommunikationsinhalt von Focusrite Control analysiere, schreibe ich den Code einmal in der Windows-Umgebung.

Analyse der Abfrageverarbeitung

Zuerst müssen wir herausfinden, wie Focusrite Control den Scarlett-Status erhält. Wenn Sie einfach denken, sollten Sie in der Lage sein, die Statusänderung zu erkennen, wenn Sie die Statusumschalttaste am Hauptgerät durch Interrupt-Übertragung drücken.

Wenn Sie am Scarlett-Hauptgerät tatsächlich INST oder PAD drücken, können Sie die folgenden Daten senden und empfangen. RECV sind die von Scarlett empfangenen Daten und SEND sind die an Scarlett übertragenen Daten.

RECV Interrupt 00 00 80 00 00 00 00 00
SEND Control   21 02 00 00 03 00 18 00 00 00 80 00 08 00 EE 99
               00 00 00 00 00 00 00 00 7C 00 00 00 18 00 00 00
RECV Control
SEND Interrupt 
RECV Interrupt 01 00 00 00 00 00 00 00
SEND Control   A1 03 00 00 03 00 28 00
RECV Control   00 00 80 00 18 00 EE 99 00 00 00 00 00 00 00 00 
               01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
               00 00 00 00 00 00 00 00

Dies ist das Ergebnis, wenn der Mikrofonmodus des Analogeingangs 1 von Scarlett 18i20 auf INST geändert wird. Selbst wenn andere Tasten gedrückt werden, hat sich der Austausch außer den letzten Daten bis auf die Seriennummer nicht geändert. Mit anderen Worten

Es scheint der Fluss zu sein. Das endgültige Format der empfangenen Daten ist

Es ist geworden.

Anfragecode

Jetzt, da ich davon weiß, werde ich einen Code schreiben, der tatsächlich nach dem Status des Analogeingangs fragt.

analogstat.py


import usb.core
import usb.backend.libusb1
from ctypes import c_void_p, c_int
backend = usb.backend.libusb1.get_backend(find_library=lambda x: "libusb-1.0.dll")
backend.lib.libusb_set_option.argtypes = [c_void_p, c_int]
backend.lib.libusb_set_debug(backend.ctx, 5)
#Nachfolgend finden Sie die Optionen für die Verwendung von usbdk
backend.lib.libusb_set_option(backend.ctx, 1)
#Scarlett 18 i20 Hersteller-ID und Produkt-ID
VENDOR_ID = 0x1235
PRODUCT_ID = 0x8215

device = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID, backend=backend)
device.set_configuration()
#Die Setup-Sequenz wird von selbst ausgeführt, wahrscheinlich aufgrund von usbdk, und die nächste Seriennummer lautet normalerweise 0x77.
device.ctrl_transfer(0x21, 0x02, 0x00, 0x03,
    [0x00, 0x00, 0x80, 0x00, 0x08, 0x00, 0x77, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x7C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00])
#Übertragungslesung unterbrechen.
#Vom Geräteendpunkt 3 lesen=83, 8 Bytes, Timeout 100 ms
ret = device.read(0x83, 8, 100)
print(' '.join(map(lambda x: '{0:0{1}x}'.format(x, 2), ret)))
ret = bytearray(device.ctrl_transfer(0xA1, 0x03, 0x00, 0x03, 0x0028))
print(' '.join(map(lambda x: '{0:0{1}x}'.format(x, 2), ret)))

Die endgültige Ausgabe des Ergebnisses der Ausführung des obigen Codes mit eingeschaltetem INST, PAD und AIR von Eingang 1, AIR von Eingang 4, PAD von Eingang 5 und AIR von Eingang 8 ist

RECV Control 00 00 80 00 18 00 77 00 00 00 00 00 00 00 00 00 
             01 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00
             01 00 00 01 00 00 00 01

Bingo. Versuchen wir eine seltsame Kommunikation, z. B. das Verschieben der Seriennummer, wenn der normale Betrieb bestätigt wird.

device.ctrl_transfer(0x21, 0x02, 0x00, 0x03,
    [0x00, 0x00, 0x80, 0x00, 0x08, 0x00, 0xFF, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x7C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00])

Senden Sie die Steuerübertragung der Analog-Eingangsstatusabfrage mit der erweiterten Seriennummer.

RECV Control 00 00 80 00 00 00 77 00 03 00 00 00 00 00 00 00

Anscheinend wird der Fehlerstatus in den letzten 8 Bytes eingegeben. Obwohl ich 40 Bytes Daten senden wollte, wurden nur 16 Bytes gesendet, aber dies ist sicherlich das Verhalten, das vom USB-Standard erkannt wird. NG nur, wenn die Datenlänge die erforderliche Größe überschreitet.


Es ist lange her, also ist es diesmal bis hierher. nächstes Mal

Versuchen wir diese beiden.

[^ 1]: https://return0.info/ Obwohl es als Hobby ein Overkill sein soll ... [^ 2]: Wir empfehlen es nicht, da es Probleme wie das Fehlen von Software-Soundquellen sowie kompatiblen Geräten gibt. Ich verwende jedoch ein Plug-In, das nur eine Binärdatei für Linux enthält, und erstens nehme ich hauptsächlich Performances auf, ohne viele Software-Soundquellen zu verwenden, damit ich qualitativ hochwertige Werke erstellen kann, die von Winkellabels aus Übersee angeboten werden. Jedoch. [^ 3]: Standarddokumente ist ziemlich umfangreich und bietet ein angemessenes Reverse Engineering wie dieses Mal Um ehrlich zu sein, ist es schwierig, es als Referenz zu verwenden. [^ 4]: Dahinter verbirgt sich die steigende Nachfrage nach Musikproduktion auf Mobil- / Tablet-Geräten, die mit iOS und Android ausgestattet sind, und es scheint, dass die Unterstützung von Geräten, für die es schwierig ist, einen dedizierten Treiber zu installieren, einen starken Aspekt aufweist. [^ 5]: Entspricht Aufnahme, Wiedergabe, Umschalten der Taktquelle digitaler Geräte, Umschalten der Abtastfrequenz. Auch im Fall eines Allzwecktreibers kann es einen Nachteil hinsichtlich der Latenz sowie hinsichtlich der Funktionalität geben. Wenn jedoch die Round-Trip-Latenz einschließlich der gesamten Verarbeitung von der Eingabe zur Ausgabe etwa 20 ms beträgt, scheint dies kein Problem zu sein. Das in professionellen Studios verwendete Pro Tools HDX scheint in der Welt von 0,7 ms zu sein.

Recommended Posts

Erstellen Sie einen Audio-Interface-Controller mit pyusb (2).
Erstellen Sie einen Audio-Interface-Controller mit pyusb (1).
Machen Sie Scrapy exe mit Pyinstaller
Stellen Sie ein Überwachungsgerät mit einem Infrarotsensor her
Verstärkungslernen 37 Starten Sie automatisch mit Ataris Wrapper
So erstellen Sie einen HTTPS-Server mit Go / Gin
Machen Sie eine Regenschirmerinnerung mit Raspberry Pi Zero W.
Ich habe versucht, eine OCR-App mit PySimpleGUI zu erstellen
Erstellen Sie mit tkinter eine Anwendung mit cx_freeze zu einer ausführbaren Datei
Bilden Sie Lambda-Schichten mit Lambda
Machen Sie eine Yuma mit Discord.py
Erstellen Sie Folien mit iPython
Machen Sie einen in die Klimaanlage integrierten Personal Computer "airpi" mit Raspberry Pi 3!