Open mungewell opened 1 year ago
Here are some other 'info' blocks - with a short 1min length. info_1min.txt info_1min_overdub.txt
Firstly we can see that the shorter length results in less data in the first section:
00000000 6c 6f 6f 70 65 72 00 00 00 00 4c 00 20 00 28 00 |looper....L. .(.|
00000010 22 00 23 00 24 00 25 00 26 00 27 00 28 00 29 00 |".#.$.%.&.'.(.).|
00000020 2a 00 2b 00 2c 00 2d 00 2e 00 2f 00 30 00 31 00 |*.+.,.-.../.0.1.|
00000030 32 00 33 00 34 00 35 00 36 00 37 00 38 00 39 00 |2.3.4.5.6.7.8.9.|
00000040 3a 00 3b 00 3c 00 3d 00 3e 00 3f 00 40 00 41 00 |:.;.<.=.>.?.@.A.|
00000050 42 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |B...............|
00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
...
And when the overdub is used on the pedal, there is a 2nd part to the first section (rather than being all zeros).
...
00000510 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000520 00 00 00 00 49 00 4a 00 8d 00 8f 00 90 00 91 00 |....I.J.........|
00000530 92 00 93 00 94 00 95 00 96 00 97 00 98 00 99 00 |................|
00000540 9a 00 9b 00 9c 00 9d 00 9e 00 9f 00 a0 00 a1 00 |................|
00000550 a2 00 a3 00 a4 00 a5 00 a6 00 a7 00 a8 00 a9 00 |................|
00000560 aa 00 ab 00 69 00 6a 00 6b 00 6c 00 6d 00 6e 00 |....i.j.k.l.m.n.|
00000570 6f 00 70 00 71 00 72 00 73 00 74 00 75 00 76 00 |o.p.q.r.s.t.u.v.|
00000580 77 00 78 00 79 00 7a 00 7b 00 7c 00 7d 00 7e 00 |w.x.y.z.{.|.}.~.|
00000590 7f 00 80 00 81 00 82 00 83 00 84 00 85 00 86 00 |................|
000005a0 87 00 88 00 89 00 00 00 00 00 00 00 00 00 00 00 |................|
000005b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
...
When downloading (TShark Log4) with the official SW, the first data blocks are:
Request data block - pt1
00000000: 00 F0 27 01 F1 03 00 F2 00 ..'......
--
Request data block - pt2
00000000: F1 F3 27 01 F1 03 00 FE 00 ..'......
--
Request data block - pt3
00000000: E2 F7 27 01 F1 03 00 09 00 ..'......
--
Request data block - pt4
00000000: D3 FB 27 01 F1 03 00 14 00 ..'......
OMG... just seeing those Requests lined up like that caused a 'light bulb' moment.
The address is 32 bits, that first byte is not a 'command' it is the 'low address byte'!
'10min' loop - no overdub.
00000000 6c 6f 6f 70 65 72 00 27 01 ff 8f 02 88 02 01 04 |looper.'........|
from 10min data stops, end of base section.
00000520 8b 02 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000a30 00 00 00 00 00 00 00 00 6c 6f 6f 70 65 72 00 30 |........looper.0|
00000a40 1a d5 19 1a 55 29 22 78 36 22 c4 86 29 fd ad 29 |....U)"x6"..)..)|
00000bc0 1e 98 87 1e e9 55 16 c3 30 16 a4 af 0d 68 6f 0d |.....U..0....ho.|
00000bd0 c4 c4 04 |...|
00000bd3
from '1min_dub'... data restarts in middle... this is the overdub
00000520 00 00 00 00 49 00 4a 00 8d 00 8f 00 90 00 91 00 |....I.J.........|
Theory time... we have three sections, first two contain data which changes length according to duration of 'base' sound. Normally the bytes count up. The third section seems to contain much more random data.
I think the first is the 'base' loop, where the numbers are indexes into the third section which actually points to the location in memory. The second section is the 'overdub' loop, if there is an overdub. Normally the indexes will be the same as the first section but when a part is overdubbed the index is replaced with a new one containing audio from 'base' and 'overdub' mixed.
This would allow recording over various bits of the 'base' loop, whilst also allow the 'over dub' to be turn on/off at will, and even cleared completely.
OK, now to code something to parse this...
Something like: parse_info.py.txt
$ python3 parse_info.py| head -n 40
Base : Overdub
0x0190 -> 0x000000
0x0191 -> 0x000000
0x0192 -> 0x000000
0x0193 -> 0x000000
0x0194 -> 0x000000
0x0195 -> 0x000000
0x0196 -> 0x000000
0x0197 -> 0x000000
0x0198 -> 0x000000
0x0199 -> 0x000000
0x019A -> 0x000000
0x019B -> 0x000000
0x019C -> 0x000000
0x019D -> 0x000000
0x019E -> 0x000000
0x019F -> 0x000000
0x01A0 -> 0x000000
0x01A1 -> 0x000000 : 0x041C -> 0x000000
0x01A2 -> 0x000000 : 0x041E -> 0x000000
0x01A3 -> 0x000000 : 0x041F -> 0x000000
0x01A4 -> 0x000000 : 0x0420 -> 0x000000
0x01A5 -> 0x000000 : 0x0421 -> 0x000000
0x01A6 -> 0x000000 : 0x0422 -> 0x000000
0x01A7 -> 0x000000 : 0x0423 -> 0x000000
0x01A8 -> 0x000000 : 0x0424 -> 0x000000
0x01A9 -> 0x000000 : 0x0425 -> 0x000000
0x01AA -> 0x000000 : 0x0426 -> 0x000000
0x01AB -> 0x000000 : 0x0427 -> 0x000000
0x01AC -> 0x000000 : 0x0428 -> 0x000000
0x01AD -> 0x000000 : 0x0429 -> 0x000000
0x01AE -> 0x000000
0x01AF -> 0x000000
0x01B0 -> 0x000000
0x01B1 -> 0x000000
0x01B2 -> 0x000000
0x01B3 -> 0x000000
0x01B4 -> 0x000000
0x01B5 -> 0x000000
0x01B6 -> 0x000000
...
slight improved version: parse_info.py.txt
I also realized a few things:
Have some confirmations.
Created a 1min loop, with multiple overdubs, of note is that the 'info' only contains the last overdub and the previous ones are 'bake' into the base loop. This make total sense.
The parse info file is here: https://github.com/mungewell/twinlooper/blob/main/tshark_log5/after/info_parse.txt
Although the file looks 'full', there is the end to the base section here:
000000f0 9c 07 9d 07 9e 07 9f 07 a0 07 a1 07 a2 07 a3 07 |................|
00000100 a4 07 a5 07 a6 07 a7 07 00 00 01 00 02 00 03 00 |................|
^^ ^^
I was able to correlate the 'info' changes, in sequence numbers, with the different addresses (from PCAP) downloaded from the pedal.
I thought there may be a mathematical relationship between index and address, however that doesn't appear so:
I scripted something to look at discontinues in the download address - allowing for the 0x38 missing a few bytes (should really be 0x3c to stay on track).
This shows that they don't all occur after the 0x38, but can exist mid 'block' and that the new location can be mid block too. full_address.txt
00000000: C4 3F 79 08 38 00 00 42 00 .?y.8..B.
00000000: 00 40 79 08 F1 03 00 49 00 .@y....I.
00000000: F1 43 79 08 F1 03 00 55 00 .Cy....U.
00000000: E2 47 79 08 F1 03 00 60 00 .Gy....`.
00000000: F1 D3 81 09 F1 03 00 BC 00 .........
00000000: E2 D7 81 09 F1 03 00 C7 00 .........
00000000: D3 DB 81 09 F1 03 00 D2 00 .........
00000000: C4 DF 81 09 38 00 00 99 00 ....8....
00000000: E2 F7 85 09 F1 03 00 A3 00 .........
00000000: D3 FB 85 09 F1 03 00 AE 00 .........
00000000: C4 FF 85 09 38 00 00 75 00 ....8..u.
00000000: C4 CF 8F 09 38 00 00 9B 00 ....8....
00000000: 00 D0 8F 09 F1 03 00 A2 00 .........
00000000: F1 D3 8F 09 F1 03 00 AE 00 .........
00000000: C4 EF 9B 08 38 00 00 70 00 ....8..p.
00000000: 00 F0 9B 08 F1 03 00 77 00 .......w.
00000000: F1 F3 9B 08 F1 03 00 83 00 .........
00000000: D3 2B A6 08 F1 03 00 5E 00 .+.....^.
00000000: C4 2F A6 08 38 00 00 25 00 ./..8..%.
Still massively confused about how the app knows which address to download.
Checked that there are no repeated address, except these two.
$ grep -A 2 -e '^1.2.1' log.decoded | grep -e '^00000000:' | cut -d ' ' -f 1-5| sort | uniq -c | grep -v "\s1\s"
2 00000000: 00 00 F3 1E
2 00000000: 62 63 64 65
0x1EF30000 - info block 0x65646362 - response to ID request
I also further dismissed the idea of a linear relationship between 'index' and 'address'.
By sorting each numerically I saw that index 'positions' (between 0.0 and 1.0) were at the extremes, whereas addresses sorted the same way covered the whole range (ie no big gaps).
So maybe I've figured a way to look at this, and map addresses (seen in PCAP) to those indexes in the 'info' block.
We know data must be downloaded in order (to render wav file), so if I number the info indexes in sequence as a fraction to number of them (ie start at 0 and up to 1). I can then also number the discontinuities in download address the same way.
Concat and sort gives me some form of map, which should tie the two domains together.....
0 0 0x021B
0.000743494423792 6 141295616 86C0000
0.008130081300813 1 0x021C
0.016260162601626 2 0x021D
0.024390243902439 3 0x021E
0.032520325203252 4 0x021F
0.039776951672863 321 141557760 8700000
0.040650406504065 5 0x025D
0.048780487804878 6 0x025F
0.056910569105691 7 0x0260
0.065040650406504 8 0x0261
0.073170731707317 9 0x0262
0.08130081300813 10 0x0263
0.089430894308943 11 0x0226
0.097560975609756 12 0x0227
0.105691056910569 13 0x0228
0.113821138211382 14 0x0229
0.121951219512195 15 0x022A
0.130081300813008 16 0x0264
0.13184634448575 1064 159503345 981D3F1
0.138211382113821 17 0x0266
0.146341463414634 18 0x0267
0.154471544715447 19 0x0268
0.16260162601626 20 0x0269
0.170731707317073 21 0x026A
0.173234200743494 1398 160419780 98FCFC4
...
As noted in #5, the pedal seems to build new 'songs' as it is cycled through connecting to PC or start/stopping the loop playback.
One interesting thing is that some of the header appears to be changing during this. For essential something is the same.
==> song2.txt <==
Header:
00000000: 6C 6F 6F 70 65 72 00 AA 02 00 EF 03 20 00 16 08 looper...... ...
^^ ^^ length in seconds?
^^ ^^ ^^ ^^ different?
00000010: B6 03 B7 03 B8 03 B9 03 BA 03 BB 03 BC 03 DA 03 ................
==> song3.txt <==
Header:
00000000: 6C 6F 6F 70 65 72 00 26 01 00 DA 03 20 00 16 08 looper.&.... ...
00000010: B6 03 B7 03 B8 03 B9 03 BA 03 BB 03 BC 03 BD 03 ................
Still can't figure a mapping, confirmed that the extra/3rd block does not exist. Must have been an error in my code.
What range of address do we actually have?
$ grep -e '6[0-9A-F] 08 F1 03 00' full_address.txt | sort
00000000: 00 00 6C 08 F1 03 00 96 00 ..l......
00000000: 00 00 6D 08 F1 03 00 95 00 ..m......
00000000: 00 00 6E 08 F1 03 00 94 00 ..n......
00000000: 00 00 6F 08 F1 03 00 93 00 ..o......
00000000: 00 10 6C 08 F1 03 00 86 00 ..l......
Thru
00000000: F1 F3 D2 09 F1 03 00 4B 00 .......K.
00000000: F1 F3 D3 09 F1 03 00 4A 00 .......J.
00000000: F1 F3 D8 09 F1 03 00 45 00 .......E.
00000000: F1 F3 D9 09 F1 03 00 44 00 .......D.
00000000: F1 F3 DA 09 F1 03 00 43 00 .......C.
00000000: F1 F3 DB 09 F1 03 00 42 00 .......B.
So: 0x086C0000 = 141295616 thru 0x09DBF3F1 = 165409777
gives a delta of 24114161 (0x16FF3F1)
Each audio block is (0x03F1) * 4 + 0x3C = 0x1000
= 4096 bytes (with extra bytes to correct addressing).
Since we don't see a lot of address discontinuities, adjacent indexes must be a whole multiple of that.
Now timing (rough calculations) Each audio block renders `(0x03F1) 4 + 0x38 - (8 5)' = 4502 byes, 24bit by 2ch = ~675 samples at 48Khz = 0.0140625s. Audio clip was ~30s long, so 2133 audio blocks need, and 124 indexes given. ~17.2 audio blocks per index.
That's too close to 16
to be a co-incidence.... so each each index would be 0x10000 bytes, and to cover the address range above you'd need a range of at least 0x16F (367) in index value. Plausible.
After 'searching' the first block of data downloaded appears to be a 'index' type object.... I assume that it points to series of blocks to download. info.txt
The first block seen in my WireShark captures is
and indeed this gives me audio.