[PYTHON] Créer un contrôleur d'interface audio avec pyusb (2)

Cela fait longtemps, mais la continuation de Dernière fois. Cette fois

Ces deux. Cependant, comme le logiciel Focusrite ne prend pas en charge Linux, vous devez effectuer la séquence d'initialisation que Windows a effectuée pour vous. Tout d'abord, de l'analyse.

Analyse de la séquence d'initialisation de Scarlett

Tout d'abord, démarrez Ratatoskr, puis allumez / éteignez la Scarlett 18i20.

VirtualBox_Windows 10_07_01_2020_00_40_15.png

Il y a une quantité considérable de communication, mais le but est de réinitialiser le numéro de série, alors faites attention à la position du numéro de série et appuyez dessus. La position du numéro de série semble être 15..16 octets, donc si vous y réfléchissez normalement, le numéro de série est 0 ou 1, et il semble que la fonction apparaisse dans la partie type de message de 9..14 octets. (* Dans l'image, divers filtres sont utilisés pour supprimer.)

En conséquence, les deux transferts de contrôle suivants ont été touchés tels quels.

SEND 21 02 00 00 03 00 10 00 00 00 00 00 00 00 01 00
SEND 21 02 00 00 03 00 10 00 02 00 00 00 00 00 01 00

J'ai envoyé le message avec le numéro de série 1 deux fois, mais il semble que le premier soit le processus de réinitialisation du numéro de série, et le second envoie normalement le message avec le numéro de série 1. Tout d'abord, écrivez le code exactement tel qu'il est et essayez d'utiliser le code d'acquisition d'état de l'appareil précédemment écrit avec le numéro de série après la réinitialisation. (Le code ci-dessous est un extrait. Voir le code précédent pour plus de détails.)

reset_seq.py


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

À propos, il semble que la valeur de la partie numéro de série de la commande de réinitialisation du numéro de série puisse être n'importe quoi.

Fonctionne sous Linux

Quand je regarde la communication avec les périphériques USB sous Linux, je pense que la méthode utilisant le wirehark est assez importante, mais je passe sous / sys / kernel / debug / usbmon et joue une sortie inutile avec grep -v. (Dans tous les cas, il est nécessaire d'installer le module usbmon.)

De plus, sous Linux, le processus d'initialisation semble être un peu différent de celui de Windows, par exemple, si vous appelez mal set_configuration, une erreur se produira.

analogstat4linux.py


import usb.core
import usb.backend.libusb1
from ctypes import c_void_p, c_int
backend = usb.backend.libusb1.get_backend()

from usb.util import CTRL_IN, CTRL_OUT, CTRL_TYPE_CLASS, CTRL_RECIPIENT_INTERFACE, build_request_type
from usb.control import get_status

VENDOR_ID = 0x1235
PRODUCT_ID = 0x8215
device = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID, backend=backend)
device.ctrl_transfer(0x21, 0x02, 0x00, 0x03,
    [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
device.ctrl_transfer(0xA1, 0x03, 0x00, 0x03, 0x0010)
device.ctrl_transfer(0x21, 0x02, 0x00, 0x03,
    [0x00, 0x00, 0x80, 0x00, 0x08, 0x00, 0x01, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x7C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00])
device.read(0x83, 8, 100)
ret = bytearray(device.ctrl_transfer(0xA1, 0x03, 0x00, 0x03, 0x0028))
print(' '.join(map(lambda x: '{0:0{1}x}'.format(x, 2), ret)))
$ sudo cat /sys/kernel/debug/usbmon/3t > dump.txt
* Exécutez le script dans un autre terminal
Ctrl-C
$ grep -v 'Z[io]:' dump.txt 
ffff95a78595f500 560234266 S Co:013:00 s 21 02 0000 0003 0010 16 = 00000000 00000100 00000000 00000000
ffff95a78595f500 560234401 C Co:013:00 0 16 >
ffff95a78595f500 560234429 S Ci:013:00 s a1 03 0000 0003 0010 16 <
ffff95a78595f500 560234646 C Ci:013:00 0 16 = 00000000 00000000 00000000 00000000
ffff95a78595f500 560234667 S Co:013:00 s 21 02 0000 0003 0018 24 = 00008000 08000100 00000000 00000000 7c000000 18000000
ffff95a78595f500 560234893 C Co:013:00 0 24 >
ffff95a78595f500 560235404 S Ii:013:03 -115 8 <
ffff95a78595f500 560235649 C Ii:013:03 0 8 = 01000000 00000000
ffff95a78595f500 560235693 S Ci:013:00 s a1 03 0000 0003 0028 40 <
ffff95a78595f500 560235776 C Ci:013:00 0 40 = 00008000 18000100 00000000 00000000 00000000 00000000 00000000 00000000

Apparemment, c'est aussi le résultat attendu. (* Étant donné que certaines conversions d'ordre des octets sont incluses, certaines parties ne correspondent pas aux résultats de l'environnement Windows)

De plus, lors de l'écriture de divers codes et de l'expérimentation, l'appareil s'est parfois bloqué en raison du délai d'expiration de l'opération, mais pour le moment, aucune méthode de récupération autre que la mise hors tension du matériel n'a été trouvée. C'est un problème futur.

Changer l'état de l'appareil avec du code Python

Enfin le sujet principal. Parmi les fonctions de la Scarlett 18i20, les fonctions qui ne peuvent pas être prises en charge par le commutateur sur l'unité principale et qui ne peuvent pas être commandées par le pilote général de Linux sont les suivantes.

Cette dernière est plutôt compliquée ou gênante, mais ce n'est pas si gênant pour moi d'utiliser [^ 2], donc en plus de la première, commutation LINE / INST IMPEDANCE [^ 3] et entrée PAD [^ 4] J'essaierai de correspondre.

Analyse telle que la commutation AIR

La procédure est presque la même qu'avant.

En conséquence, la communication suivante semble être une commutation AIR.

Séquence (1)
SEND: 21 02 00 00 00 03 00 19 01 00 80 00 09 00 01 00 00 00 00 00 00 00 00 00 8c 00 00 00 01 00 00 00 01
SEND: 03 00 00 00 03 00 10 
RECV: 01 00 80 00 00 00 01 00 00 00 00 00 00 00 00 00

Séquence (2)
SEND: 21 02 00 00 00 03 00 14 02 00 80 00 04 00 02 00 00 00 00 00 00 00 00 00 08 00 00 00
SEND: 03 00 00 00 03 00 10 
RECV: 01 00 80 00 00 00 02 00 00 00 00 00 00 00 00 00

En raison de la commutation IMPEDANCE etc., le transfert de commande de sortie dans la séquence de changement d'état d'entrée analogique (1) semble être dans le format suivant.

Les détails du 25e octet sont les suivants.

Aussi, je me demandais ce que signifiait le transfert de contrôle de sortie de la séquence (2), mais il semble que ce soit une commande de commutation d'affichage de l'indicateur sur l'unité principale. ** Si vous n'envoyez pas ce message, les indicateurs INST / PAD / AIR de l'unité principale ne changeront pas. ** **

Code récapitulatif jusqu'à présent

Ce qui suit est le code qui commute l'état AIR de l'entrée analogique 1 à chaque exécution.

switch_air.py


import usb.core
import usb.backend.libusb1
from ctypes import c_void_p, c_int
backend = usb.backend.libusb1.get_backend()

from usb.util import CTRL_IN, CTRL_OUT, CTRL_TYPE_CLASS, CTRL_RECIPIENT_INTERFACE, build_request_type
from usb.control import get_status

VENDOR_ID = 0x1235
PRODUCT_ID = 0x8215
device = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID, backend=backend)
device.ctrl_transfer(0x21, 0x02, 0x00, 0x03,
    [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
device.ctrl_transfer(0xA1, 0x03, 0x00, 0x03, 0x0010)

#Demande de statut
device.ctrl_transfer(0x21, 0x02, 0x00, 0x03,
    [0x00, 0x00, 0x80, 0x00, 0x08, 0x00, 0x01, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x7C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00])
device.read(0x83, 8, 100)
ret = bytearray(device.ctrl_transfer(0xA1, 0x03, 0x00, 0x03, 0x0028))
stat = ret[32] #AIR avec entrée analogique 1

device.ctrl_transfer(0x21, 0x02, 0x00, 0x03, [0x01, 0x00, 0x80, 0x00, 0x09, 0x00, 0x02, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x8C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
    stat ^1]) #Changer d'état avec XOR
device.ctrl_transfer(0xA1, 0x03, 0x00, 0x03, 0x0010)

#Indicateurs de commutation
device.ctrl_transfer(0x21, 0x02, 0x00, 0x03, [0x02, 0x00, 0x80, 0x00, 0x04, 0x00, 0x03, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00])
device.ctrl_transfer(0xA1, 0x03, 0x00, 0x03, 0x0010)



Le code que je développe actuellement est disponible ci-dessous.

Je suis tellement occupé que je suis complètement hors de contrôle

Si vous répondez à l'une des conditions ci-dessus, veuillez coopérer [^ 6]

[^ 1]: fonction permettant de changer la qualité du son pendant l'enregistrement du microphone en une fonction qui émule le préampli micro le plus vendu de la société. Si vous ne pouvez pas l'utiliser, cela ne vaut pas la peine d'acheter pour 56000 yens. [^ 2]: Pendant le travail d'enregistrement, lors de l'enregistrement du signal d'entrée avec un PC, il est parfois connecté directement à la sortie pour un contrôle sans latence, il est donc préférable de jouer avec la table de mixage intégrée. [^ 3]: comme l'impédance du signal circulant diffère selon l'équipement, changez-la. [^ 4]: Diminue le gain pour une entrée excessive. [^ 5]: Il est nécessaire de concevoir en fonction de la situation, comme effacer le journal une fois avec F4 une fois la séquence de démarrage terminée, et réduire avec un filtre comme mentionné la dernière fois. Est-il important de ne pas effectuer d'opérations supplémentaires? [^ 6]: Je ne sais pas combien de personnes sont au Japon. J'ai trouvé deux personnes faisant des choses similaires à l'étranger.

Recommended Posts

Créer un contrôleur d'interface audio avec pyusb (2)
Créer un contrôleur d'interface audio avec pyusb (1)
Créer un exe Scrapy avec Pyinstaller
Fabriquer un appareil de surveillance avec un capteur infrarouge
Apprentissage par renforcement 37 Démarrez automatiquement avec l'enrubanneuse Atari
Comment créer un serveur HTTPS avec Go / Gin
Faire un rappel de parapluie avec Raspberry Pi Zero W
J'ai essayé de créer une application OCR avec PySimpleGUI
Faire une application utilisant tkinter un fichier exécutable avec cx_freeze
Créer des couches Lambda avec Lambda
Créez un Yuma avec Discord.py
Créer des diapositives avec iPython
Fabriquez un climatiseur intégré à un ordinateur personnel "airpi" avec Raspberry Pi 3!