Open mungewell opened 1 year ago
It is the self.dev.set_configuration()
call which is failing.
After seeing the note in #2 I blacklisted usb_snd_audio
and then set_configuration()
completed, however i then got another error.
$ python3 loopertrx.py rx test.wav
parsed arg
created Cli
Device found
Detached
configuration
found USB device
Traceback (most recent call last):
File "/usr/local/lib/python3.6/dist-packages/pyusb-1.0.2-py3.6.egg/usb/core.py", line 223, in get_interface_and_endpoint
KeyError: 1
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "loopertrx.py", line 297, in <module>
main()
File "loopertrx.py", line 289, in main
dev.receive_file(args.filename)
File "loopertrx.py", line 130, in receive_file
size = self.get_size()
File "loopertrx.py", line 85, in get_size
self.dev.write(self.ENDPOINT_OUT, header)
File "/usr/local/lib/python3.6/dist-packages/pyusb-1.0.2-py3.6.egg/usb/core.py", line 940, in write
File "/usr/local/lib/python3.6/dist-packages/pyusb-1.0.2-py3.6.egg/usb/core.py", line 102, in wrapper
File "/usr/local/lib/python3.6/dist-packages/pyusb-1.0.2-py3.6.egg/usb/core.py", line 215, in setup_request
File "/usr/local/lib/python3.6/dist-packages/pyusb-1.0.2-py3.6.egg/usb/core.py", line 102, in wrapper
File "/usr/local/lib/python3.6/dist-packages/pyusb-1.0.2-py3.6.egg/usb/core.py", line 231, in get_interface_and_endpoint
ValueError: Invalid endpoint address 0x1
It seems that the Rowin pedal uses a different endpoint (0x02). lsusb_vv.txt
Changing this and I got a timeout
.... we're making progress.
$ python3 loopertrx.py rx test.wav
parsed arg
created Cli
found USB device
[Errno 110] Operation timed out
As noted in title, it appears that this pedal uses the Midi/SysEx protocol (not the Mass-Storage protocol). So there would be some reverse engineering required to make it work...
The biggest challenge here is working out how the official code packs the Midi data. As midi is 7-bit, the 8-bit bytes need to be split in some way.
We know that previously the code used 1024 (1000??) byte blocks of audio data, this seems to fit with the 1173 (7-bit) blocks we see. 1173 * 7 / 8 = 1026.735
Looking at some of the Midi data, it looks like (and makes sense) that there is a length field sent before the data, this might be counted in bits...
f000320d493f0040007127627b107e00000000000000000000000000000000000000000000000000000000000
LLLLLLMr<--
L = 00,3f,49 = (63 * 128) + 73 = 8137 bits
f000320d4100004000622f627b604b00001e01f7
LLLLLLMr<--20c,10b=70bits-->Cs
L = 00,00,41 = 65 bits
f000320d3126004000622f627b604b00000000000000000000000000000000000000000000000000000000000
LLLLLLMr<--
L = 00,26,31 = (38 * 128) + 49 = 4913 bits
f0003245000000407ff7
LLLLLLMrCs
L = 0
f000324558010040306246112b666c193461440d23564c5933680200282062040a152c5c40112301f7
LLLLLLMr<--- 62 chars, 31 bytes, each 7bit -> 217 bits ---->Cs
L = 00,01,58 (7 bit) = 88 + (1 * 128) = 216 bits?
The next question is how they pack the data.. although this could be several schemes, given they appear to count bits this might just be a sequential bit field pack.
ie
8-bit packed to 7bit (LSB)
11111111 --> _1111111
22222222 __2222221
33333333 ___3333322
44444444 ____4444333
...4444
Well using this idea for the packing, it looks like:
$ amidi -p hw:2,0,0 -S 'F0 00 32 45 00 00 00 40 7f F7' -t 2 -r test.bin
41 bytes read
$ hexdump -C test.bin
00000000 f0 00 32 45 58 01 00 40 30 62 46 11 2b 66 6c 19 |..2EX..@0bF.+fl.|
00000010 34 61 44 0d 23 56 4c 59 33 68 02 00 28 20 62 04 |4aD.#VLY3h..( b.|
00000020 0a 15 2c 5c 40 11 23 01 f7 |..,\@.#..|
00000029
Decodes into something plausible.
$ python3 pack_test.py
216
00000000: 30 B1 31 B2 32 B3 33 B4 30 B1 31 B2 32 B3 33 B4 0.1.2.3.0.1.2.3.
00000010: 00 80 02 89 09 8A 0A 8B 0B 8C 8C ...........
None
What about audio packets?
From WireShark log on #1 we have PC->Pedal packet(s) with 2358 bytes each. If we unpack
these it looks like the first few bytes might be something different (ie not audio). But output[7:]
results in 2048 bytes per packet and gives us a nice clear output waveform.
$ python3 pack_test.py | grep -e "000000[0123]"
00000000: 00 00 BC 96 02 FF 03 00 80 BC 7F 00 BF 7F 80 C2 ................
00000010: 7F 00 C6 7F 80 C8 7F 80 CC 7F 80 CF 7F 80 D2 7F ................
00000020: 80 D5 7F 80 D8 7F 80 DB 7F 00 DE 7F 00 E1 7F 00 ................
00000030: E4 7F 00 E6 7F 80 E9 7F 00 ED 7F 00 F0 7F 00 F2 ................
$ python3 pack_test.py | tail
00000780: 1A 00 00 17 00 00 12 00 00 0F 00 80 0B 00 80 07 ................
00000790: 00 00 03 00 80 FF 7F 00 FB 7F 80 F6 7F 00 F3 7F ................
000007A0: 00 EE 7F 80 EA 7F 80 E5 7F 00 E1 7F 80 DD 7F 80 ................
000007B0: D9 7F 80 D5 7F 00 D2 7F 80 CE 7F 80 CB 7F 80 C8 ................
000007C0: 7F 80 C5 7F 80 C2 7F 80 BF 7F 80 BD 7F 00 BB 7F ................
000007D0: 00 B9 7F 80 B7 7F 80 B4 7F 00 B2 7F 00 B0 7F 00 ................
000007E0: AE 7F 00 AC 7F 80 AA 7F 00 A8 7F 00 A7 7F 80 A4 ................
000007F0: 7F 80 A3 7F 80 A2 7F 00 A1 7F 80 9E 7F 00 9E 7F ................
00000800: 80 9D 7F 80 9C 7F 0D .......
None
$ ls -al stream.raw
-rw-rw-r-- 1 simon simon 2048 Jan 25 12:02 stream.raw
$ sox -r 48k -e signed -b 24 -c 1 --endian little stream.raw stream.wav
Next step is to see if I can script up grabbing packets from log (rather than manually copying/processing) and chain them together to recover whole audio clip.
Not programmatic, but I was able to tshark
to dump all the packets are text and then grep out the ones I wanted. A bit of substitution and I have them as Python b"string"
.
They stitch together OK, but there is something wrong with the way bytes are being interpreted as audio - causing high level signals to be clipped/inverted... maybe I just have things miss-aligned.
For reference I used:
$ sox -r 48k -e signed -b 24 -c 1 --endian big stream.raw stream.wav
$ soxi stream.wav
Input File : 'stream.wav'
Channels : 1
Sample Rate : 48000
Precision : 24-bit
Duration : 00:00:03.52 = 169136 samples ~ 264.275 CDDA sectors
File Size : 507k
Bit Rate : 1.15M
Sample Encoding: 24-bit Signed Integer PCM
Basically it looks like the data is just plain weird... if you use 3bytes (for 24bit) the 3rd byte is just 00
or 01
depending on whether the 2nd byte is +ve or -ve.
Never seen this this before, and can't bend Sox to decode it...
$ hexdump -v -e '/1 "%02X\n"' stream.raw | awk '!(NR%3){print q,p,$0}{q=p;p=$0}'
9E FD 01
86 FD 01
6A FD 01
4C FD 01
36 FD 01
1E FD 01
0E FD 01
FA FC 01
E8 FC 01
D8 FC 01
CA FC 01
BC FC 01
B2 FC 01
...
0C FF 01
26 FF 01
42 FF 01
62 FF 01
7E FF 01
98 FF 01
B4 FF 01
CA FF 01
E2 FF 01
02 00 00
18 00 00
32 00 00
46 00 00
64 00 00
7A 00 00
90 00 00
A6 00 00
So if we don't output the 3rd byte and treat the raw data as 16bit signed, we get a usable audio file. stream.wav.zip
$ python3 pack_test.py
$ sox -r 48k -e signed -b 16 -c 1 --endian little stream.raw stream.wav
I got the code 'talking' to the pedal, and it can perform the 'search' part - looking for recording to download.
$ python3 search_download.py
Found pedal:
00000000: 30 B1 31 B2 32 B3 33 B4 30 B1 31 B2 32 B3 33 B4 0.1.2.3.0.1.2.3.
00000010: 00 80 02 89 09 8A 0A 8B 0B 8C 8C ...........
None
Unpacked Response:
00000000: 80 21 00 00 10 00 00 01 00 00 00 16 27 00 00 0B .!..........'...
00000010: 28 DF F8 E4 16 DF F8 15 (.......
None
Checking Address: 0xbcf8
Unpacked Response:
00000000: 00 00 F8 BC 07 01 00 00 07 00 0B ...........
None
Checking Address: 0xbcf0
Unpacked Response:
00000000: 00 00 F0 BC 07 01 00 80 31 80 08 ........1..
None
...
You may need to change the midiname
that the code looks for. For me the Rowin Twin Looper reports as DFU
.
I found that initially my pedal didn't report any 'addresses', giving response with 0xFF or 0x7F. Then I filled the whole 10mins up with audio, and now it reports different values.
I have attempted to code the next stage, of downloading the sample block. But this is not working yet... It's also worth noting that the official app doesn't work for me, giving an error whenever it is started.
Finally got the official Software working, the "Data Length Error" seems to be that it's trying to communicate on the wrong Midi interface. I had a Akai Midi/Network driver installed, when I disabled that the software would see the pedal.
Given that I have not seen others comment, and I have an increasing amount of code... I might spin up my own project to cover this pedal. Thoughts...?
This is where I'm at. I am able to 'search' and then download the first block. This is very rough code, lots to be tested and understood.
For example the data should be a 1Khz wave, which I can't pull out of the data...
$ python3 search_download.py
Found pedal:
00000000: 30 B1 31 B2 32 B3 33 B4 30 B1 31 B2 32 B3 33 B4 0.1.2.3.0.1.2.3.
00000010: 00 80 02 89 09 8A 0A 8B 0B 8C 8C ...........
None
00000000: 00 32 0D 41 00 00 00 00 00 43 00 00 00 02 00 00 .2.A.....C......
00000010: 4E 00 N.
None
00000000: 00 C0 10 00 00 08 00 00 27 ........'
None
Packed response:
00000000: 00 00 43 00 00 00 02 00 00 01 00 00 00 60 62 09 ..C..........`b.
00000010: 00 00 16 20 79 0D 1F 39 0B 5F 71 57 ... y..9._qW
None
Unpacked Response:
00000000: 00 C0 10 00 00 08 00 80 00 00 00 00 8B 13 00 80 ................
00000010: 05 94 6F 7C 72 8B 6F FC 0A ..o|r.o..
None
Checking Address: 0xbcf8
Unpacked Response:
00000000: 00 00 F8 BC 07 01 00 00 07 00 0B ...........
None
Download Address: 0xbcf8
Unpacked Response:
00000000: 00 00 F8 BC 87 F8 01 00 07 00 80 0F 00 80 1F 00 ................
00000010: 00 2B 00 00 BA FF FF 56 00 00 A5 FF 7F 70 00 00 .+.....V.....p..
00000020: E9 FF FF B7 FF FF E0 FF FF 0B 00 00 22 00 80 29 ............"..)
00000030: 00 80 F0 FF FF B5 FF FF 2B 00 80 25 00 00 86 00 ........+..%....
00000040: 80 03 00 00 30 00 00 26 00 00 E9 FF FF 24 00 80 ....0..&.....$..
00000050: C4 FF 7F 02 00 80 DD FF 7F 21 00 00 D4 FF FF 1C .........!......
00000060: 00 00 17 00 80 02 00 00 1E 00 00 08 00 80 68 00 ..............h.
00000070: 80 E9 FF FF 0D 00 00 E1 FF 7F 07 00 00 B1 FF FF ................
00000080: 4E 00 80 1C 00 80 27 00 00 16 00 00 EC FF FF ED N.....'.........
00000090: FF 7F EF FF 7F 0A 00 80 F3 FF FF FA FF FF D5 FF ................
000000A0: FF 2B 00 80 FA FF 7F F8 FF FF FC FF 7F D5 FF FF .+..............
000000B0: 35 00 00 FB FF FF C1 FF 7F 08 00 80 2C 00 80 CE 5...........,...
000000C0: FF 7F 99 FF FF BB FF FF F3 FF FF 3E 00 80 4B 00 ...........>..K.
000000D0: 00 0D 00 80 C3 FF 7F 25 00 00 4C 00 00 0F 00 00 .......%..L.....
000000E0: C2 FF FF 1F 00 80 DA FF FF 16 00 80 08 00 00 B7 ................
000000F0: FF FF 03 00 80 29 00 80 40 00 00 BA FF 7F 1E 00 .....)..@.......
00000100: 00 BE FF FF ED FF FF 1C 00 80 2A 00 80 E6 FF FF ..........*.....
00000110: 05 00 80 1E 00 00 C6 FF 7F B2 FF 7F EC FF 7F 1B ................
00000120: 00 80 E6 FF FF 5C 00 80 23 00 80 F3 FF FF 34 00 .....\..#.....4.
00000130: 80 EF FF FF 63 FF 7F 60 00 00 DC FF 7F 07 00 00 ....c..`........
00000140: 1C 00 00 1F 00 80 06 00 00 08 00 00 C9 FF 7F 48 ...............H
00000150: 00 00 CE FF 7F 0F 00 00 0E 00 80 01 00 80 0B 00 ................
00000160: 80 01 00 00 F5 FF 7F 21 00 80 3F 00 00 D0 FF FF .......!..?.....
00000170: D3 FF 7F EE FF FF 13 00 80 5B 00 80 48 00 00 FB .........[..H...
00000180: FF FF 31 00 00 C9 FF 7F E6 FF 7F 2E 00 80 FD FF ..1.............
00000190: 7F A1 FF FF DA FF 7F 89 FF 7F FF FF 7F 3D 00 00 .............=..
000001A0: A5 FF FF 08 00 00 1E 00 00 02 00 80 CE FF 7F 0C ................
000001B0: 00 00 BA FF FF F9 FF 7F CE FF FF 9C FF 7F 05 00 ................
000001C0: 00 FC FF FF 4C 00 00 E3 FF 7F EF FF FF BA FF 7F ....L...........
000001D0: 22 00 00 34 00 80 03 00 80 DD FF FF D7 FF 7F 31 "..4...........1
000001E0: 00 80 C1 FF FF 0C 00 00 09 00 00 3B 00 80 BD FF ...........;....
000001F0: 7F EF FF 7F DC FF FF D5 FF FF 10 00 00 0B 00 00 ................
00000200: C0 FF FF AE FF FF 35 00 80 BC FF 7F AD FF FF 34 ......5........4
00000210: 00 80 1E 00 00 EA FF FF D4 FF FF 1C 00 80 10 00 ................
00000220: 80 D1 FF FF 24 00 00 D0 FF 7F F6 FF 7F 88 FF FF ....$...........
00000230: FA FF 7F C5 FF FF 15 00 80 1A 00 80 DD FF FF 30 ...............0
00000240: 00 80 C7 FF FF 33 00 00 E6 FF FF A8 FF FF 56 00 .....3........V.
00000250: 00 39 00 80 EB FF FF 31 00 00 EF FF FF F5 FF FF .9.....1........
00000260: E4 FF 7F BF FF 7F 4D 00 80 E1 FF 7F E7 FF 7F 07 ......M.........
00000270: 00 00 E8 FF FF A0 FF 7F C9 FF 7F 24 00 80 55 00 ...........$..U.
00000280: 80 FF FF FF CA FF FF 3B 00 80 03 00 80 D5 FF 7F .......;........
00000290: FF FF 7F 10 00 00 F6 FF 7F 28 00 00 10 00 80 06 .........(......
000002A0: 00 80 D8 FF FF EA FF 7F 15 00 00 60 00 80 07 00 ...........`....
000002B0: 80 FA FF FF AC FF FF B2 FF FF B3 FF 7F 0A 00 80 ................
000002C0: C7 FF FF F8 FF FF 68 FF FF D4 FF 7F CB FF 7F D9 ......h.........
000002D0: FF FF 1B 00 80 B9 FF 7F D1 FF 7F 0C 00 00 E9 FF ................
000002E0: 7F EF FF FF F3 FF FF 3F 00 00 B5 FF 7F 6B 00 80 .......?.....k..
000002F0: 06 00 80 FA FF 7F 3A 00 80 E4 FF 7F DA FF FF D7 ......:.........
00000300: FF FF 1A 00 00 00 00 80 FE FF FF 1A 00 00 BA FF ................
00000310: 7F 83 00 00 F4 FF 7F 97 00 00 FA FF FF 14 00 00 ................
00000320: E6 FF 7F F9 FF FF 2B 00 00 0C 00 80 51 00 80 B8 ......+.....Q...
00000330: FF FF 70 FF 7F B8 FF FF A1 FF 7F EC FF FF C3 FF ..p.............
00000340: 7F 28 00 80 17 00 00 EC FF FF F6 FF FF 1C 00 80 .(..............
00000350: C7 FF 7F 0A 00 80 06 00 00 CC FF FF B8 FF FF D4 ................
00000360: FF FF 19 00 00 50 00 00 07 00 00 FD FF FF 1F 00 .....P..........
00000370: 80 95 FF 7F 17 00 00 04 00 80 ED FF 7F 0A 00 80 ................
00000380: 35 00 00 F0 FF 7F F0 FF 7F F9 FF 7F F8 FF FF E0 5...............
00000390: FF FF D1 FF FF 58 00 00 FF FF FF 04 00 00 20 00 .....X........ .
000003A0: 00 CC FF 7F 48 00 00 34 00 80 4C 00 80 EA FF FF ....H..4..L.....
000003B0: 3B 00 00 F0 FF 7F 27 00 00 E3 FF 7F D6 FF 7F CF ;.....'.........
000003C0: FF FF 25 00 00 01 00 80 A5 FF 7F B3 FF FF 9B FF ..%.............
000003D0: FF 2F 00 80 57 00 80 F0 FF FF E4 FF FF BE FF FF ./..W...........
000003E0: FD FF FF 1A 00 00 BA FF FF 01 00 00 C5 FF 7F 89 ................
000003F0: 00 00 0C 00 00 CD FF 7F F2 11 ..........
None
I've put my code here: https://github.com/mungewell/twinlooper
Please come and make it better ;-)
As per title, I've picked up the Rowin Twin Looper pedal (similar construction to other brands).
It identifies as
With the UDEV and script changed to different ID, running the script fails and causes the pedal to detach it's midi port.
Prior to runnig the script, it DOES respond to the same midi as noted for the AP-09 (bug #1).