Barsik-Barbosik / Zoom-Firmware-Editor

MIT License
193 stars 27 forks source link

More information on drum patterns? #17

Open mungewell opened 5 years ago

mungewell commented 5 years ago

The project mentions changing the drum patterns.... has any work been done on this?

Is there a 'file' within the F/W image (like a 'zdl' or something) which contains the patterns, and if so has any of it been decoded?

mungewell commented 4 years ago

Zoom just announced the A1Four/A1FourX, which apart from different effects have a couple of other interesting things. 1). Drum patterns are different. 2). Looper can be placed either before or after effects chain.

Obviously no F/W available yet, but will good to look at these features when it is...

Tomlinsky commented 4 years ago

They don't appear to be in the standard SMF format I would half have have expected,given their history of manufacturing rhythm machines. I could be wrong on this though, still investigating. I would expect patterns still to have delta trigger timings for hits of each pattern but without knowing the format this will,obviously, be tricky.

This ties in with what I am trying to unravel. Knowing the actual structure of ZDL (in my case) or ZD2 files would open up a whole new world allowing new effects to be programmed. Much of them appear to be graphic data and crap spewed from the linker. Using simple effects, such as LineSel, would reveal much about the hardware froma coding point of view and I would love to be able to recreate the ZDL format.

Willkeep nibbling away at it as and when I have time here. Great work by the way, your guys information is a great help.

Tomlinsky commented 4 years ago

Oh, to answer your initial question... The drum patterns, samples, rhythm and looper(s) code are in the BIN folder of the firmware updaters self-contained resources. In the case of the G5n/G1Xon, at least, it is filename "129".

PS: Pondering on my wish to code for the devices, all I actualy need is to know where the code segment is in a ZDL as I should then be able to use existing effects as a template. I assume a checksumor three isinvolved but will deal with that later. I should be abletoworkout how the hardware is mapped with that information. No definitve joy, sofar...

Tomlinsky commented 4 years ago

Further information on drum patterns. In the resource mentioned, and others, areas appear to be dilineated by the ASCII string "YSX". Using SMF format, although logical and easier to mod, would have been inefficient as there is no need here for things such as individual note off, velocity, volume/etc information and complete overkill. All that is needed in a simple rhythm loop player like this are patterns of delta timings, which can be easily manipulated for tempo changes and a trigger number (1 of 24 in this case I believe). Each would only need to be 8 bits and I would expect at least an end marker for each pattern but that isn't a given as the player may be working from a list start addresses and lengths. There are a number of areas that look interesting. I'm only scanning in between other things here in case a penny drops.

Also, my wish to get some code into the puppies is looking suspect at this point as I'm beginning to believe that code is decrypted by the boot ROM(s) upon transfer. In which case ZOOM did their job properly. sigh

Tomlinsky commented 4 years ago

Okay, I have found what I believe to be indexes to the rhythm patterns. But at this point I don't understand what file they are indexing or what the baseline for the index is. But it's a start. Perhaps.

mungewell commented 4 years ago

Wow you seem to be 'storming ahead'! I attempted to find the '129' file, but my Java-Fu is weak. How can I get a copy of the file? Either by using the f/w tool, or downloading from the device. For files like this it may be helpful to view as hex, as you say it only needs to contain 'events' for the drum hits... perhaps this are encoded into a binary blob.

Tomlinsky commented 4 years ago

The installer executables are zip archives, just extract them. I actually have no use for this rhythm stuff personally but am intrigued at the moment. Need another cuppa, this actuallymay be simpler than I thought...

Tomlinsky commented 4 years ago

Actually, being able to install a setup with less effects but more complex rhythms would be useful thinking about it....

Tomlinsky commented 4 years ago

If you look at the section where the sample filenames are there is a string of 7 bytes directly before each pattern name each terminated by C0. There are possibly 8 - 10 bytes in the string but the first three are zeroes, the first of which I suspect is a string terminator from the preceding filename. Some examples...

04 04 02 20 B7 0D C0 ; Guide 04 04 02 58 B2 0D C0 ; 8Beats1 04 04 02 88 87 0D C0 ; 8Beats2 04 04 02 18 87 0D C0 ; 8Beats3 04 04 02 58 85 0D C0 ; 16Beats1 04 04 02 E8 6A 0D C0 ; 16Beats2 04 04 02 48 6A 0D C0 ; 16Beats3 ... 05 04 02 58 94 0D C0 ; CtWaltz1 03 04 02 78 A9 0D C0 ; CtWaltz2 03 04 02 B8 A2 0D C0 ; JzWaltz1 03 04 02 F0 AE 0D C0 ; JzWaltz2 03 04 02 98 A0 0D C0 ; Metro3 03 04 02 C8 B4 0D C0 ; Metro4 04 04 02 A8 B3 0D C0 ; Metro5 05 04 02 70 B2 0D C0 ; Metro

Bytes 3-5 look like poiners to me as they are generally linear as you work through the list, C0 a terminator/identifier/padding with others control bytes of some kind. IF they are pointers.the only file big enough to contain data with a 24 bit offset is file "136" in the updater resources.

Or bytes 3-4 could be a 16 bit pointer...

mungewell commented 4 years ago

I think that the size and the contents show that the '129' file is very much more than just the drum patterns. There is a section which looks like it is assigning which sounds are used for which pattern...

00064D20: 00 03 04 02 30 02 18 C0  4A 7A 57 61 6C 74 7A 31  ....0...JzWaltz1
00064D30: 00 00 00 00 00 00 00 00  00 00 00 00 00 53 6E 72  .............Snr
00064D40: 41 6D 62 2E 72 61 77 00  00 53 6E 72 32 2E 72 61  Amb.raw..Snr2.ra
00064D50: 77 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  w...............
00064D60: 00 00 00 00 00 00 00 00  00 00 00 00 00 52 69 64  .............Rid
00064D70: 65 2E 72 61 77 00 00 00  00 00 00 00 00 00 00 00  e.raw...........
00064D80: 00 00 00 00 00 4B 69 6B  41 6D 62 2E 72 61 77 00  .....KikAmb.raw.
00064D90: 00 43 6C 69 63 6B 2E 72  61 77 00 00 00 03 04 02  .Click.raw......
00064DA0: 10 0F 18 C0 4A 7A 57 61  6C 74 7A 32 00 4B 69 6B  ....JzWaltz2.Kik
00064DB0: 32 2E 72 61 77 00 00 00  00 53 6E 72 41 6D 62 2E  2.raw....SnrAmb.
00064DC0: 72 61 77 00 00 53 6E 72  32 2E 72 61 77 00 00 00  raw..Snr2.raw...
00064DD0: 00 53 6E 72 34 2E 72 61  77 00 00 00 00 48 48 46  .Snr4.raw....HHF
00064DE0: 2E 72 61 77 00 00 00 00  00 52 69 64 65 2E 72 61  .raw.....Ride.ra
00064DF0: 77 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  w...............
00064E00: 00 4B 69 6B 41 6D 62 2E  72 61 77 00 00 43 6C 69  .KikAmb.raw..Cli
00064E10: 63 6B 2E 72 61 77 00 00  00 03 04 02 40 00 18 C0  ck.raw......@...
00064E20: 4D 65 74 72 6F 33 00 00  00 00 00 00 00 00 00 00  Metro3..........
00064E30: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064E40: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064E50: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064E60: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064E70: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064E80: 00 00 00 00 00 00 00 00  00 43 6C 69 63 6B 2E 72  .........Click.r
00064E90: 61 77 00 00 00 03 04 02  80 14 18 C0 4D 65 74 72  aw..........Metr
00064EA0: 6F 34 00 00 00 00 00 00  00 00 00 00 00 00 00 00  o4..............

I'd suspect that the numbers ahead of the name define the number of samples/etc, so these should be easily parsable.

mungewell commented 4 years ago

So we are both typing at the same time... ;-) BTW ZT2 files were using fixed length strings for file names.

Tomlinsky commented 4 years ago

Oh it's a hell of a lot more than drum patterns , It contains the looper(s) and rhythm player code (possibly encrypted and as fixed modules) and tuner parts of the deal as well. There has to be a structure for each pattern for, at least, what samples are in each pattern (kit) and timings (deltas probably). I reckon these are pointers to those structures. It's playing one loop effectively and resetting according to tempo. Simple stuff. Just can't find the structures. Youd imagine there would be data with plenty of low numbers (0-23) dotted around with 68 patterns in there somewhere. Things like hihats repeat plenty within a bar on some patterns. Unless that's, as I suspect, it in which case they are likely pointers directly to the patterns. If 16 bit, subtracting 220h from each number seems logical but not hit on anything so far that makes sense as pattern data.

Yep, fixed length filenames. Hadn't noticed that. So, 7 byte strings at this point it is then.

Actually, there's a simple way to test if they are indeed pointers...

Ha, soz using it as instant messaging here. :)

mungewell commented 4 years ago

Things I'd expect:

Rather than a table of sample numbers, it may be a bit field of the drum sounds used in each beat.

One thing to question is whether the pattern info is before or after the pattern name... the last item seems to suggest after

00064F90: 98 10 18 C0 4D 65 74 72  6F 00 00 00 00 00 00 00  ....Metro.......
00064FA0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064FB0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064FC0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064FD0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064FE0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064FF0: 00 00 00 00 00 00 00 00  00 00 00 00 00 43 6C 69  .............Cli
00065000: 63 6B 2E 72 61 77 00 00  00_04_04_01_D8_15_18_C0  ck.raw.......... <--- is this the data for Metro
00065010: 00 41 5F 69 6E 69 74 69  61 6C 69 7A 65 64 50 61  .A_initializedPa
00065020: 72 61 6D 73 3A 20 75 6E  69 6E 69 74 69 61 6C 69  rams: uninitiali
00065030: 7A 65 64 20 50 61 72 61  6D 73 20 73 74 72 75 63  zed Params struc
Tomlinsky commented 4 years ago

It doesn't even need no of beats per bar or number of bars. It's only playing one pass then retriggering. Delatas would do on their own. It could have that information but not really needed for such a simple player.

I can't add to the archive here. I've copied the 8Beats1 7 string over 8Beats2 and 8Beats3 and want to update firmware to see if 8Beats1, 8Beats2 and 8Beats3 will then all play the same. If so, they are pattern pointers.

mungewell commented 4 years ago

Looking at your list of "data; name", the data matches previous name.... waltz are in 3/4 time, and metro3/4/5 are 3/4/5 beats. All with 2 bars.

mungewell commented 4 years ago

It may need to know time signature, as the looper can be set to bar/note lengths. Drum and looper tempo interact.

Tomlinsky commented 4 years ago

It still only needs deltas. Not saying it doesn't have that info but that's how I'd do it in such a simple setup. Start... Deltas per hit... Reset/retrigger. Also, you'll notice that the looper/rhythm can't resync. ;)

mungewell commented 4 years ago

Do all the definitions have the same length (124 bytes), and same number of (potential) samples?

If we work on the assumption that data contains time sig and number of bars... what do the other 3 bytes mean? 0xC0 is likely a teminator, do the others imply offset (ie have nominal distance between them for 4/4 2 bars)?

000636E0: 46 75 6E 6B 32 00 00 00  00 4B 69 6B 31 2E 72 61  Funk2....Kik1.ra
000636F0: 77 00 00 00 00 53 6E 72  41 6D 62 2E 72 61 77 00  w....SnrAmb.raw.
00063700: 00 53 6E 72 33 2E 72 61  77 00 00 00 00 53 6E 72  .Snr3.raw....Snr
00063710: 32 2E 72 61 77 00 00 00  00 48 48 43 2E 72 61 77  2.raw....HHC.raw
00063720: 00 00 00 00 00 48 48 4F  2E 72 61 77 00 00 00 00  .....HHO.raw....
00063730: 00 48 48 43 41 6D 62 2E  72 61 77 00 00 4B 69 6B  .HHCAmb.raw..Kik
00063740: 41 6D 62 2E 72 61 77 00  00 43 6C 69 63 6B 2E 72  Amb.raw..Click.r
00063750: 61 77 00 00 00 04 04 02  B0 C7 17 C0              aw..........Funk

vs

00064F10:                          4D 65 74 72 6F 35 00 00  ....`...Metro5..
00064F20: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064F30: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064F40: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064F50: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064F60: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064F70: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064F80: 00 43 6C 69 63 6B 2E 72  61 77 00 00 00 05 04 02  .Click.raw......
00064F90: 98 10 18 C0                                       ....Metro.......

00064F90:             4D 65 74 72  6F 00 00 00 00 00 00 00  ....Metro.......
00064FA0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064FB0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064FC0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064FD0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064FE0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064FF0: 00 00 00 00 00 00 00 00  00 00 00 00 00 43 6C 69  .............Cli
00065000: 63 6B 2E 72 61 77 00 00  00 04 04 01 D8 15 18 C0  ck.raw..........
mungewell commented 4 years ago

Doesn't the pattern get displayed with dots, coloured in as pattern is played...?

Most are 4/4 time, what does "12/8 Grv" do (12/8 time)?

Tomlinsky commented 4 years ago

Okay, updated installer. I think...

mungewell commented 4 years ago

Another thing I note about the 'offsets'; yours mostly have '0x0D' as last byte and mine have '0x17' (B1 Four f/w).

Tomlinsky commented 4 years ago

it's only bytes 3-4 possibly. May not be, but these are certainlynot the patterns... and they must be somewhere!

Tomlinsky commented 4 years ago

Okay, I replaced 8Beats2 string with the one from 8Beats1 updated the firmware and they now play exactly the same pattern. This will have odd effects if simply done across patterns randomly as different patterns have different kits.

Tomlinsky commented 4 years ago

I reckon indexes, either...

04 04 - 02 20 - B7 0D C0 ; Guide 04 04 - 02 58 - B2 0D C0 ; 8Beats1 04 04 - 02 88 - 87 0D C0 ; 8Beats2 04 04 - 02 18 - 87 0D C0 ; 8Beats3 04 04 - 02 58 - 85 0D C0 ; 16Beats1 04 04 - 02 E8 - 6A 0D C0 ; 16Beats2 04 04 - 02 48 - 6A 0D C0 ; 16Beats3

or less likely (Although code is running in a TMS320C6745 and dependant however the memory is mapped) ...

04 04 - 02 20 B7 - 0D C0 ; Guide 04 04 - 02 58 B2 - 0D C0 ; 8Beats1 04 04 - 02 88 87 - 0D C0 ; 8Beats2 04 04 - 02 18 87 - 0D C0 ; 8Beats3 04 04 - 02 58 85 - 0D C0 ; 16Beats1 04 04 - 02 E8 6A - 0D C0 ; 16Beats2 04 04 - 02 48 6A - 0D C0 ; 16Beats3

The numbers increase pretty linearly to my eyes.

Tomlinsky commented 4 years ago

Each "pattern header" is 124 bytes long containing the identified string of 7 bytes along with fixed file-length sample filenames. However, a sample named in a kit does not necessarily mean it is actually used as evidenced by the first pattern header in the GFX1on. Where it actually only uses Kik1.raw and HHC.raw other samples are declared.

GUIDE����Kik1.raw����SnrAmb.raw��Snr1.raw����������������HHC.raw�����������������HHCAmb.raw��KikAmb.raw��Click.raw���X² À

Up to 9 samples slots are available per pattern and any unused slot may, or may not, be padded with zeroes. Unused samples listed in a header look to be preloads for next or previous patterns which would suggest that samples are loaded dynamically into user memory.

mungewell commented 4 years ago

I think your interpretation is correct (name, sample filenames), but I am not convinced about the other data. I think these bytes are (in order), time-sig1, time-sig2 and number of bars.... likely followed (as you suggested) by an offset in code/memory to the actual data defining the pattern.

Most have '0x02', except for the 'Metro' pattern which has '0x01' - this one displays on device as "O O O O".

00064F90:             4D 65 74 72  6F 00 00 00 00 00 00 00  ....Metro.......
00064FA0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064FB0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064FC0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064FD0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064FE0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00064FF0: 00 00 00 00 00 00 00 00  00 00 00 00 00 43 6C 69  .............Cli
00065000: 63 6B 2E 72 61 77 00 00  00 04 04 01 D8 15 18 C0  ck.raw.......... = D8 15 18

The other oddity is '12/8 Grv' which displays as "O o o O o o O o o O o o"

00064940:                          31 32 2F 38 20 47 72 76  ........12/8 Grv
00064950: 00 4B 69 6B 31 2E 72 61  77 00 00 00 00 53 6E 72  .Kik1.raw....Snr
00064960: 41 6D 62 2E 72 61 77 00  00 53 6E 72 31 2E 72 61  Amb.raw..Snr1.ra
00064970: 77 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  w...............
00064980: 00 48 48 43 2E 72 61 77  00 00 00 00 00 00 00 00  .HHC.raw........
00064990: 00 00 00 00 00 00 00 00  00 48 48 43 41 6D 62 2E  .........HHCAmb.
000649A0: 72 61 77 00 00 4B 69 6B  41 6D 62 2E 72 61 77 00  raw..KikAmb.raw.
000649B0: 00 43 6C 69 63 6B 2E 72  61 77 00 00 00 0C 08 02  .Click.raw......
000649C0: E8 CA 17 C0                                       ....Waltz....Kik = E8 CA 17
mungewell commented 4 years ago

The "offsets" are not in sequence, for the B1 Four F/W (apparently different to your dataset) they can be sorted as follows. The difference between them is not consistent, which might suggest a variable length data block.

simon@thevoid:~$ sort offset.txt 
 17 B8 D0  =  000645E0: D0 B8 17 C0 53 6B 61 00  00 00 00 00 00 4B 69 6B  ....Ska......Kik 
 17 BE D0  =  00064100: 61 77 00 00 00 04 04 02  D0 BE 17 C0 52 26 42 32  aw..........R&B2 
 17 C0 40  =  00064460: 63 6B 2E 72 61 77 00 00  00 04 04 02 40 C0 17 C0  ck.raw......@... 
 17 C0 F8  =  00063F10: 61 77 00 00 00 04 04 02  F8 C0 17 C0              aw..........ROCK 
 17 C2 60  =  00064370: 00 04 04 02 60 C2 17 C0  50 6F 70 00 00 00 00 00  ....`...Pop..... 
 17 C3 10  =  000634E0: 63 6B 2E 72 61 77 00 00  00 04 04 02 10 C3 17 C0  ck.raw.......... 
 17 C5 10  =  00063200: 00 04 04 02 10 C5 17 C0                           ........Rock1... 
 17 C5 B8  =  000643F0: B8 C5 17 C0 50 6F 70 52  6F 63 6B 00 00 4B 69 6B  ....PopRock..Kik 
 17 C6 60  =  00063E90: 63 6B 2E 72 61 77 00 00  00 04 04 02 60 C6 17 C0  ck.raw......`... 
 17 C7 08  =  000636D0: 63 6B 2E 72 61 77 00 00  00 04 04 02 08 C7 17 C0  ck.raw.......... 
 17 C7 B0  =  00063750: 61 77 00 00 00 04 04 02  B0 C7 17 C0              aw..........Funk 
 17 C8 58  =  00064750: 00 04 04 02 58 C8 17 C0  46 75 73 69 6F 6E 00 00  ....X...Fusion.. 
 17 C9 00  =  00063B30: 61 77 00 00 00 04 04 02  00 C9 17 C0 42 6C 75 65  aw..........Blue 
 17 C9 A8  =  00063180: 61 77 00 00 00 04 04 02  A8 C9 17 C0              aw..........16Be 
 17 CA 48  =  00063100: 63 6B 2E 72 61 77 00 00  00 04 04 02 48 CA 17 C0  ck.raw......H... 
 17 CA E8  =  000649C0: E8 CA 17 C0 57 61 6C 74  7A 00 00 00 00 4B 69 6B  ....Waltz....Kik 
 17 CB 80  =  00064940: 00 04 04 02 80 CB 17 C0  31 32 2F 38 20 47 72 76  ........12/8 Grv 
 17 CC 18  =  000637D0: 00 04 04 02 18 CC 17 C0                           ........JazzFunk 
 17 CC B0  =  000635E0: 00 04 04 02 B0 CC 17 C0  45 6D 6F 00 00 00 00 00  ........Emo..... 
 17 CD 48  =  00064200: 48 CD 17 C0 39 30 73 20  53 6F 75 6C 00 4B 69 6B  H...90s Soul.Kik 
 17 CD E0  =  000642F0: 61 77 00 00 00 04 04 02  E0 CD 17 C0 44 69 73 63  aw..........Disc 
 17 CE 70  =  00063850: 70 CE 17 C0 4D 6F 74 6F  77 6E 00 00 00 4B 69 6B  p...Motown...Kik 
 17 D0 20  =  000638C0: 63 6B 2E 72 61 77 00 00  00 04 04 02 20 D0 17 C0  ck.raw...... ... 
 17 D1 40  =  00063C30: 40 D1 17 C0 4A 61 7A 7A  31 00 00 00 00 00 00 00  @...Jazz1....... 
 17 D1 C8  =  000647D0: C8 D1 17 C0 53 77 69 6E  67 31 00 00 00 4B 69 6B  ....Swing1...Kik 
 17 D2 50  =  00064080: 63 6B 2E 72 61 77 00 00  00 04 04 02 50 D2 17 C0  ck.raw......P... 
 17 D7 58  =  00064180: 00 04 04 02 58 D7 17 C0  37 30 73 20 53 6F 75 6C  ....X...70s Soul 
 17 D7 D8  =  00063AB0: 63 6B 2E 72 61 77 00 00  00 04 04 02 D8 D7 17 C0  ck.raw.......... 
 17 D8 30  =  00063470: 30 DB 17 C0 4D 74 6C 43  6F 72 65 00 00 4B 69 6B  0...MtlCore..Kik 
 17 D8 58  =  00064270: 63 6B 2E 72 61 77 00 00  00 04 04 02 58 D8 17 C0  ck.raw......X... 
 17 DA B8  =  00064B30: 00 04 04 02 B8 DA 17 C0  42 72 65 61 6B 73 33 00  ........Breaks3. 
 17 DB A8  =  000644E0: 61 77 00 00 00 04 04 02  A8 DB 17 C0 45 75 72 6F  aw..........Euro 
 17 DC 20  =  00063370: 61 77 00 00 00 04 04 02  20 DC 17 C0 48 61 72 64  aw...... ...Hard 
 17 DC 98  =  00064010: 98 DC 17 C0                                       ....TomTomBt.Kik 
 17 DD F0  =  00063090: F0 DD 17 C0                                       ....16Beats1.Kik 
 17 DE 60  =  000633F0: 00 04 04 02 60 DE 17 C0  48 65 61 76 79 4D 74 6C  ....`...HeavyMtl 
 17 DE D0  =  000632F0: 63 6B 2E 72 61 77 00 00  00 04 04 02 D0 DE 17 C0  ck.raw.......... 
 17 DF 40  =  00063010: 00 04 04 02 40 DF 17 C0                           ....@...8Beats3. 
 17 DF B0  =  00062F90: 61 77 00 00 00 04 04 02  B0 DF 17 C0              aw..........8Bea 
 17 E0 20  =  00064AB0: 61 77 00 00 00 04 04 02  20 E0 17 C0 42 72 65 61  aw...... ...Brea 
 17 E0 90  =  00063280: 90 E0 17 C0 52 6F 63 6B  32 00 00 00 00 4B 69 6B  ....Rock2....Kik 
 17 E1 68  =  000639C0: 00 04 04 02 68 E1 17 C0  52 6F 63 6B 65 72 73 00  ....h...Rockers. 
 17 E1 D0  =  00064BB0: D0 E1 17 C0 35 2F 34 20  47 72 76 00 00 4B 69 6B  ....5/4 Grv..Kik 
 17 E2 38  =  000646D0: 61 77 00 00 00 04 04 02  38 E2 17 C0 53 68 75 66  aw......8...Shuf 
 17 F0 80  =  00063DA0: 00 04 04 02 80 F0 17 C0  42 6F 73 73 61 32 00 00  ........Bossa2.. 
 17 F0 E0  =  00063E20: E0 F0 17 C0 53 61 6D 62  61 31 00 00 00 4B 69 6B  ....Samba1...Kik 
 17 F2 00  =  000648C0: 61 77 00 00 00 04 04 02  00 F2 17 C0 31 32 2F 38  aw..........12/8 
 17 F3 10  =  00063660: 10 F3 17 C0 46 75 6E 6B  31 00 00 00 00 4B 69 6B  ....Funk1....Kik 
 17 F3 68  =  00063560: 61 77 00 00 00 04 04 02  68 F3 17 C0 46 61 73 74  aw......h...Fast 
 17 F5 78  =  00064560: 00 04 04 02 78 F5 17 C0  4E 65 77 57 61 76 65 00  ....x...NewWave. 
 17 F5 D0  =  00063A40: D0 F5 17 C0 32 6E 64 20  4C 69 6E 65 00 4B 69 6B  ....2nd Line.Kik 
 17 F6 28  =  00064650: 63 6B 2E 72 61 77 00 00  00 04 04 02 28 F6 17 C0  ck.raw......(... 
 17 F6 80  =  00064840: 63 6B 2E 72 61 77 00 00  00 04 04 02 80 F6 17 C0  ck.raw.......... 
 17 F6 D8  =  00064C20: 63 6B 2E 72 61 77 00 00  00 05 04 02 D8 F6 17 C0  ck.raw.......... 
 17 F8 F8  =  00063BB0: 00 04 04 02 F8 F8 17 C0  42 6C 75 65 73 32 00 00  ........Blues2.. 
 17 F9 40  =  00063940: 61 77 00 00 00 04 04 02  40 F9 17 C0 53 74 65 70  aw......@...Step 
 17 F9 D0  =  00063F90: 00 04 04 02 D0 F9 17 C0                           ........R'n'R... 
 18 00 08  =  00063D20: 61 77 00 00 00 04 04 02  08 00 18 C0 42 6F 73 73  aw..........Boss 
 18 00 40  =  00064E10: 63 6B 2E 72 61 77 00 00  00 03 04 02 40 00 18 C0  ck.raw......@... 
 18 00 78  =  00064A30: 63 6B 2E 72 61 77 00 00  00 03 04 02 78 00 18 C0  ck.raw......x... 
 18 02 30  =  00064D20: 00 03 04 02 30 02 18 C0  4A 7A 57 61 6C 74 7A 31  ....0...JzWaltz1 
 18 07 C0  =  00064CA0: 61 77 00 00 00 03 04 02  C0 07 18 C0 43 74 57 61  aw..........CtWa 
 18 0A E8  =  00063CA0: 63 6B 2E 72 61 77 00 00  00 04 04 02 E8 0A 18 C0  ck.raw.......... 
 18 0F 10  =  00064DA0: 10 0F 18 C0 4A 7A 57 61  6C 74 7A 32 00 4B 69 6B  ....JzWaltz2.Kik 
 18 10 80  =  00062F10: 63 6B 2E 72 61 77 00 00  00 04 04 02 80 10 18 C0  ck.raw.......... 
 18 10 98  =  00064F90: 98 10 18 C0                                       ....Metro....... 
 18 12 60  =  00064F10: 00 04 04 02 60 12 18 C0                           ....`...Metro5.. 
 18 14 80  =  00064E90: 61 77 00 00 00 03 04 02  80 14 18 C0 4D 65 74 72  aw..........Metr 
 18 15 D8  =  00065000: 63 6B 2E 72 61 77 00 00  00 04 04 01 D8 15 18 C0  ck.raw.......... 
 18 15 E8  =  00062EA0: E8 15 18 C0                                       ....GUIDE....Kik
Tomlinsky commented 4 years ago

The only reason I doubt the first 3 bytes are not bars/beats is that here some funkier time sigs would be declared as...

0C 08 02 88 6B 0D C0 ; Waltz - Possibly 05 04 02 58 94 0D C0 ; CtWaltz1 - ?? 03 04 02 C8 B4 0D C0 ; Metro4 - ?? 04 04 02 A8 B3 0D C0 ; Metro5 - ??

Again, only basing on how I would implement on a device like this, the idea of beats and bars in these devices is notional. It's triggering samples equal distances apart in time and resetting the start point at a predetermined time. All that is needed is a timer, some deltas that can be scaled for tempo and it will aways be in time with itself. We hear beats/bars but the code doesn't need to know the first thing about it as it can all be translated into "beats/bars" in a numerical form basically using division. If the patterns were linkable then that would be a completely different kettle of doohdah.

But you could be right :)

Either way, that pattern data is somewhere.

Tomlinsky commented 4 years ago

Actually, that can possibly be tested as well by putting the string for what is known to be 3/4 pattern into a 4/4 pattern header thinking about it. I don't even use the !"£$% rhythm thing!

Tomlinsky commented 4 years ago

So, my Guide pattern now plays a heavy metal waltz. I can replace the first three bytes with the original guide first 3 bytes and see what happens for a laugh...

mungewell commented 4 years ago

It looks like you are using the data BEFORE the name, I think you should be look after.... ie. at the end of the block.

000649C0:             57 61 6C 74  7A 00 00 00 00 4B 69 6B  ....Waltz....Kik
000649D0: 31 2E 72 61 77 00 00 00  00 53 6E 72 41 6D 62 2E  1.raw....SnrAmb.
000649E0: 72 61 77 00 00 53 6E 72  32 2E 72 61 77 00 00 00  raw..Snr2.raw...
000649F0: 00 00 00 00 00 00 00 00  00 00 00 00 00 48 48 43  .............HHC
00064A00: 2E 72 61 77 00 00 00 00  00 00 00 00 00 00 00 00  .raw............
00064A10: 00 00 00 00 00 48 48 43  41 6D 62 2E 72 61 77 00  .....HHCAmb.raw.
00064A20: 00 4B 69 6B 41 6D 62 2E  72 61 77 00 00 43 6C 69  .KikAmb.raw..Cli
00064A30: 63 6B 2E 72 61 77 00 00  00 03 04 02 78 00 18 C0  ck.raw......x... = 78 00 18
                                      ^^ ^^ 3/4 time!
Tomlinsky commented 4 years ago

Ah, the string is at the END of the header. There are strings before and after the headers here that have skewed things. Anyway, going to try changing the first 3 bytes to something from a known 4\4 string. You're right, yep. The surrounding strings must be fluff or test patterns. I copied it into the correct place by mistake and it confused the hell out of me why the pattern changed.

Tomlinsky commented 4 years ago

Right, bars/beats it is. That fluff skewed all of the pattern associations. What I'm not understanding, is why isn't a different pattern being played? The associations with the patterns, wherever they are, must be somewhere else. Ah well, it's a start. Logically, the pattern data should be in that same block. Although the next section looks interesting...

Tomlinsky commented 4 years ago

Okay, the next section is the pattern data unless there is some voodoo going on here. Breaking it down into 32 byte chunks yields 68 data strings (with some yet undetermined stuff at the end). An example of how I am currently interpreting the first few "patterns" after experiments would be...

Dummy (This is a fluff pattern in the G1Xon which also threw me earlier on) 2C D7 0D C0 00 09 00 00 B8 05 09 C0 B4 05 09 C0 B0 05 09 C0 C0 05 09 C0 C0 05 09 C0 A8 05 09 C0 Guide (Pattern 1) A2 05 09 C0 98 05 09 C0 90 05 09 C0 8A 05 09 C0 86 05 09 C0 C0 05 09 C0 C0 05 09 C0 C0 05 09 C0 8Beats1 (Pattern 2) C0 05 09 C0 C0 05 09 C0 82 05 09 C0 7A 05 09 C0 C0 05 09 C0 C0 05 09 C0 C0 05 09 C0 C0 05 09 C0 etc

They may not all be referenced in order by the software but if we replace the 7 byte pattern header and pattern string of "8Beats1" with those of "Guide" (first pattern on G1Xon) then when the firmware is updated we find that .... both patterns play the same!

Be aware that the device will probably crash while booting if a pattern string is injected that requires undefined samples.

Of course, this could all just be nonsense and I've been poring over graphic data for the past few hours. :)

Tomlinsky commented 4 years ago

Upon further experimentation something not right there. Am back to the indexing idea on those extraneous pattern header bytes. Will spend another evening on it, got a lot going on and always get drawn into distractions at these points for some weird psychological reason. :)

So...

8Beats1 38 42 65 61 74 73 31 00 00 ; Pattern Name - (8Beats1) 4B 69 6B 31 2E 72 61 77 00 00 00 00 ; Sample filename Slot 1 - (Kik1.raw) 53 6E 72 41 6D 62 2E 72 61 77 00 00 ; Sample filename Slot 2 - (SnrAmb.raw) 53 6E 72 31 2E 72 61 77 00 00 00 00 ; Sample filename Slot 3 - (Snr1.raw) 00 00 00 00 00 00 00 00 00 00 00 00 ; Sample filename Slot 4 - (Empty) 48 48 43 2E 72 61 77 00 00 00 00 00 ; Sample filename Slot 5 - (HHC.raw) 00 00 00 00 00 00 00 00 00 00 00 00 ; Sample filename Slot 6 - (Empty) 48 48 43 41 6D 62 2E 72 61 77 00 00 ; Sample filename Slot 7 - (HHCAmb.raw) 4B 69 6B 41 6D 62 2E 72 61 77 00 00 ; Sample filename Slot 8 - (KikAmb.raw) 43 6C 69 63 6B 2E 72 61 77 00 00 00 ; Sample filename Slot 9 - (Click.raw) 04 04 ; Time Signature 02 ; Bars 88 87 ; ?? 0D ; ?? Device dependant constant C0 ; Header terminator

mungewell commented 4 years ago

Re 0D ; ?? Device dependant constant

I think that your earlier suggestion that this (and preceeding 2 bytes?) might be a pointer may be correct. The G1Four and B1Four both use 0x17 and 0x18 (ie different in the same file). The processor for these devices is know to be different and may have a different memory map.

Some of common deltas for these supposed pointers are: 56, 88, 112, 136, 152, 168

One thought on locating the pattern data, for simple patterns each bar is likely the same. So if it's not automatically repeated by the F/W then we should see some data repeated.

Oh, that procrastination monster ;-)

Tomlinsky commented 4 years ago

Aye, a 24 bit address in a TMS320 memory map is perfectly normal. You would think the patterns should be optically identifialble indeed. They are definitely pointers, just swap any set of those numbers over here and the patterns change to different instrumentation if they are defined.

A chunk of data that neatly breaks down into 70 patterns or yet another structure.

By the way, there are 70 pattern headers declared here but two are not used by the firmware. One of the extra patterns is a dummy, the other called 12\8 Tri which is another shuffle pattern. Oh, the pattern declaration order isn't the same as on the device either.

Tomlinsky commented 4 years ago

The thing that deters me from belieiving they are 24 bit pointers is the however you interpret them the data range is too large for a bunch of timing data. The data size in total shouldn't be very large with the two bytes prior to the terminator being enough I would have thought. I'll try a few experiments on a new updater.

Tomlinsky commented 4 years ago

A thought that I had earlier today, but forgot about as usual, was that they could be bit patterns for overlaying timing data. That would be more efficient on a simple player such as this. It would literally only need a dozen or so delta timing patterns to make enough variations for what are on offer here. The footprint would be very small. The trigger hits could be tied to the timing data and the sounds changed by changing the sample associated with a slot in the header and if a trigger in an overlay isn't required in a pattern then just leave the slot empty.

Tomlinsky commented 4 years ago

Yep. They appear to be, at least, 16 bit pattern bitmaps (indirect indexes). I just replaced...

with...

and I get a kind of hybrid of the two. Then if on top of that I replace...

with...

it is yet another pattern. And if just for the hell of it...

is now replaced with...

a dodgy dance version of Time by Pink Floyd can be recreated complete with 7 dot on-screen display.

Still not a clue what the last byte is.

Okay, that'senough for me for a bit as I have other things that need sorting out.

Keep up the good work guys. Laterz. :)

Tomlinsky commented 4 years ago

On a break here and wanted to leave some notes for posterity...

The rhythm player appears to be a basic 8\9 channel tracker style implementation. Once the format of the data is worked out, which will require quite a bit of experimentation and firmware reflashing, this alone is a very flexible arrangement for building rhythm loops in a small footprint given easy access to variable bar lengths. Replacing data with dummy values until pennies drop should give results. Eventually.

BUT, there's always one isn't there, for the idea of adding user rhythms to be of any real practical use in the G\B devices an external player editor/arranger would really need to be impemented. Even a basic arranger using stock data would be able to create complex loops and would need to be to inject new samples\data into a firmware updater. Even if it only used the built in timing\trigger data and rearranged them as a basis this, coupled with changing samples\bar lengths\time sigs\deltas, would add a lot of functionality to the units.

What flags are available for such things as one shot\repeat\delta repeat\delta offset\etc on trigger data is yet to be explored. There is , at least, a method for controlling volume of a trigger. I may have a trawl\experiment here when time allows.

The following data is from a G1Xon\v1.21:

Pattern Header format: 38 42 65 61 74 73 31 00 00 ; Pattern Name - (8Beats1) 4B 69 6B 31 2E 72 61 77 00 00 00 00 ; Sample filename Slot 1 - (Kik1.raw) 53 6E 72 41 6D 62 2E 72 61 77 00 00 ; Sample filename Slot 2 - (SnrAmb.raw) 53 6E 72 31 2E 72 61 77 00 00 00 00 ; Sample filename Slot 3 - (Snr1.raw) 00 00 00 00 00 00 00 00 00 00 00 00 ; Sample filename Slot 4 - (Empty) 48 48 43 2E 72 61 77 00 00 00 00 00 ; Sample filename Slot 5 - (HHC.raw) 00 00 00 00 00 00 00 00 00 00 00 00 ; Sample filename Slot 6 - (Empty) 48 48 43 41 6D 62 2E 72 61 77 00 00 ; Sample filename Slot 7 - (HHCAmb.raw) 4B 69 6B 41 6D 62 2E 72 61 77 00 00 ; Sample filename Slot 8 - (KikAmb.raw) 43 6C 69 63 6B 2E 72 61 77 00 00 00 ; Sample filename Slot 9 - (Click.raw) 04 04 ; Time Signature - (String 0-1) 02 ; Number of measures - (String 2) 88 87 ; Pattern Bitmap - (String 3-4) 0D ; ?? - (Flags?) C0 ; Header terminator - (String 6)

Note: It looks that Click.raw needs to always be defined in Slot 9

Pattern Strings - (70 declared):

04 04 02 20 B7 0D C0 ; Dummy - (Not used) 04 04 02 58 B2 0D C0 ; GUIDE 04 04 02 88 87 0D C0 ; 8Beats1 04 04 02 18 87 0D C0 ; 8Beats2 04 04 02 58 85 0D C0 ; 16Beats3 04 04 02 E8 6A 0D C0 ; 16Beats1 04 04 02 48 6A 0D C0 ; 16Beats2 04 04 02 70 64 0D C0 ; 16beats3 04 04 02 68 88 0D C0 ; Rock1 04 04 02 38 86 0D C0 ; Rock2 04 04 02 F8 83 0D C0 ; Rock3 04 04 02 C8 85 0D C0 ; HardRock 04 04 02 08 83 0D C0 ; HeavyMtl 04 04 02 18 63 0D C0 ; MtlCore 04 04 02 90 8F 0D C0 ; Punk 04 04 02 50 6D 0D C0 ; FastPunk 04 04 02 38 8F 0D C0 ; Emo 04 04 02 68 66 0D C0 ; Funk1 04 04 02 10 67 0D C0 ; Funk2 04 04 02 B8 6C 0D C0 ; FunkRock 04 04 02 F8 77 0D C0 ; JazzFunk 04 04 02 18 79 0D C0 ; Motown 04 04 02 B0 99 0D C0 ; OneDrop 04 04 02 D8 88 0D C0 ; Steppers 04 04 02 F0 90 0D C0 ; Rockers 04 04 02 C0 7E 0D C0 ; 2ndLine 04 04 02 60 68 0D C0 ; Country 04 04 02 68 99 0D C0 ; Blues1 04 04 02 A8 79 0D C0 ; Blues2 04 04 02 E8 AA 0D C0 ; Jazz1 04 04 02 60 A0 0D C0 ; Jazz2 04 04 02 38 8B 0D C0 ; Bossa1 04 04 02 98 8B 0D C0 ; Bossa2 04 04 02 C0 65 0D C0 ; Samba1 04 04 02 00 61 0D C0 ; Samba2 04 04 02 88 9A 0D C0 ; ROCKABLY 04 04 02 70 84 0D C0 ; R'n'R 04 04 02 B8 7A 0D C0 ; TomTomBt 04 04 02 68 5D 0D C0 ; R&B1 04 04 02 40 7E 0D C0 ; R&B2 04 04 02 E8 6D 0D C0 ; 70s Soul 04 04 02 40 7F 0D C0 ; 90s Soul 04 04 02 68 77 0D C0 ; HipHop 04 04 02 68 62 0D C0 ; Disco 04 04 02 18 65 0D C0 ; Pop 04 04 02 48 60 0D C0 ; PopRock 04 04 02 80 83 0D C0 ; IndiePop 04 04 02 98 90 0D C0 ; Europop 04 04 02 B0 59 0D C0 ; NewWave 04 04 02 48 91 0D C0 ; Ska 04 04 02 A8 89 0D C0 ; Shuffle1 04 04 02 B8 67 0D C0 ; Shuffle2 04 04 02 30 7A 0D C0 ; Fusion 04 04 02 A0 91 0D C0 ; Swing1 04 04 02 78 8D 0D C0 ; Swing2 04 04 02 20 6C 0D C0 ; 12/8 Tri - (Not used) 0C 08 02 88 6B 0D C0 ; 12/8 Grv 03 04 02 D0 A0 0D C0 ; Waltz 04 04 02 F8 87 0D C0 ; Breaks1 04 04 02 90 82 0D C0 ; Breaks2 04 04 02 40 89 0D C0 ; Breaks3 05 04 02 58 94 0D C0 ; 5\4 Grv 03 04 02 78 A9 0D C0 ; CtWaltz1 03 04 02 B8 A2 0D C0 ; CtWaltz2 03 04 02 F0 AE 0D C0 ; JzWaltz1 03 04 02 98 A0 0D C0 ; JzWaltz2 03 04 02 C8 B4 0D C0 ; Metro3 04 04 02 A8 B3 0D C0 ; Metro4 05 04 02 70 B2 0D C0 ; Metro5 04 04 01 00 B7 0D C0 ; Metro

There is also an 8 byte preamble at the start of the pattern headers section preceding the headers themselves. These are likely to be relevant if new timing\trigger information is required instead of the predefined patterns:

80 85 0C C0 04 35 01 00

zeroeth commented 4 years ago

@Tomlinsky Great work on the patterns! Will be fun to add pattern editing to the G1on!

re the zdl format, I've seen the same debugger strings in the firmware. Haven't dove in but I know the chip zoom uses is the TI tms320c6745ptp (tms320c6x family) at least on the ms50. And yeah it would be fun to pick apart a simple one. Best bet is to try and throw the zdl files at a disassembler that supports it!

mungewell commented 4 years ago

Getting back to this whilst off work at the moment... wrote a little python script to decode that table of patterns/samples from the binary blobs of the F/W. decode_patterns.zip

It appears that the new v2.00 F/W contain exactly the same data (G1 vs B1 vs G1X vs B1X), but the table is in a different location ('-O' for offset) to the v1.10 F/W.

C:\Users\simon\Documents\ZoomFW>python decode_patterns.py -O 407304 -d "B1 FOUR_v2.00\unzipped\.rsrc\1041\BIN\129" > "B1 FOUR_v2.00"\patterns.txt                       
C:\Users\simon\Documents\ZoomFW>python decode_patterns.py -O 407304 -d "B1X FOUR_v2.00\unzipped\.rsrc\1041\BIN\129" > "B1X FOUR_v2.00"\patterns.txt
C:\Users\simon\Documents\ZoomFW>python decode_patterns.py -O 407304 -d "G1X FOUR_v2.00\unzipped\.rsrc\1041\BIN\129" > "G1X FOUR_v2.00"\patterns.txt
C:\Users\simon\Documents\ZoomFW>python decode_patterns.py -O 407304 -d "G1 FOUR_v2.00\unzipped\.rsrc\1041\BIN\129" > "G1 FOUR_v2.00"\patterns.txt

C:\Users\simon\Documents\ZoomFW>python decode_patterns.py -O 405032 -d B1_FOUR_v1.10_Win_E\unzipped\.rsrc\1041\BIN\129 > B1_FOUR_v1.10_Win_E\patterns.txt
C:\Users\simon\Documents\ZoomFW>python decode_patterns.py -O 405032 -d G1_FOUR_v1.10_Win_E\unzipped\.rsrc\1041\BIN\129 > G1_FOUR_v1.10_Win_E\patterns.txt

Also v2.00 vs v1.10 has different values for the 'bit map' for each pattern.... I still suspect that this is a pointer to a location in memory where the actual pattern data is stored.

mungewell commented 4 years ago

I did some looking at the 'offset' for the tables. Manually, and way too late into the night ;-)

As noted already the v2.00 F/W has different values for the offset compared to v1.10, however if you sort these offsets and then compare to calculate the number of bytes between them there is a very strong correlation between the F/Ws.

Mostly the drum pattern's data is the same 'length' (delta in 'offset'), although there are some slight changes for some. More complex patterns have a larger 'length'. pattern_matching

The annotated files are here: b1f_v200_patterns.txt b1f_v110_patterns.txt

mungewell commented 4 years ago

I had made some copy+paste errors on the v1.10 report... now it's almost 100% correlation b1f_v110_patterns.txt

Offset is annotated "from -> to, length", "length" is almost identical. Will need to figure out where in the binaries these chunks of data are....

ListContainer:                          ListContainer: 
    ListContainer:                          ListContainer: 
        Container:                              Container: 
            name = u'Dummy' (total 5)                           name = u'Dummy' (total 5)
            offset = 1578848 (last in list)           |             offset = 1578472 (last in list)
        Container:                              Container: 
            name = u'GUIDE' (total 5)                           name = u'GUIDE' (total 5)
            offset = 1577392 -> 1577416 24            |             offset = 1577088 -> 1577112 24
        Container:                              Container: 
            name = u'8Beats1' (total 7)                         name = u'8Beats1' (total 7)
            offset = 1564992 -> 1565104 112           |             offset = 1564592 -> 1564704 112
        Container:                              Container: 
            name = u'8Beats2' (total 7)                         name = u'8Beats2' (total 7)
            offset = 1564880 -> 1564992 112           |             offset = 1564480 -> 1564592 112
        Container:                              Container: 
            name = u'8Beats3' (total 7)                         name = u'8Beats3' (total 7)
            offset = 1564432 -> 1564544 112           |             offset = 1564144 -> 1564256 112
        Container:                              Container: 
            name = u'16Beats1' (total 8)                        name = u'16Beats1' (total 8)
            offset = 1559400 -> 1559560 160           |             offset = 1559112 -> 1559272 160
        Container:                              Container: 
            name = u'16Beats2' (total 8)                        name = u'16Beats2' (total 8)
            offset = 1559240 -> 1559400 160           |             offset = 1558952 -> 1559112 160
        Container:                              Container: 
            name = u'16Beats3' (total 8)                        name = u'16Beats3' (total 8)
            offset = 1558064 -> 1558232 168           |             offset = 1557776 -> 1557944 168
        Container:                              Container: 
            name = u'Rock1' (total 5)                           name = u'Rock1' (total 5)
            offset = 1565216 -> 1565328 112           |             offset = 1564816 -> 1565032 216
        Container:                              Container: 
            name = u'Rock2' (total 5)                           name = u'Rock2' (total 5)
            offset = 1564656 -> 1564880 224           |             offset = 1564368 -> 1564480 112
        Container:                              Container: 
            name = u'Rock3' (total 5)                           name = u'Rock3' (total 5)
            offset = 1563968 -> 1564088 120           |             offset = 1563680 -> 1563800 120
        Container:                              Container: 
            name = u'HardRock' (total 8)                        name = u'HardRock' (total 8)
            offset = 1564544 -> 1564656 112           |             offset = 1564256 -> 1564368 112
        Container:                              Container: 
            name = u'HeavyMtl' (total 8)                        name = u'HeavyMtl' (total 8)
            offset = 1563728 -> 1563848 120           |             offset = 1563440 -> 1563560 120
        Container:                              Container: 
            name = u'MtlCore' (total 7)                         name = u'MtlCore' (total 7)
            offset = 1557552 -> 1558064 512           |             offset = 1557264 -> 1557776 512
        Container:                              Container: 
            name = u'Punk' (total 4)                            name = u'Punk' (total 4)
            offset = 1569936 -> 1570464 528           |             offset = 1569640 -> 1570168 528
        Container:                              Container: 
            name = u'FastPunk' (total 8)                        name = u'FastPunk' (total 8)
            offset = 1560016 -> 1560168 152           |             offset = 1559728 -> 1559880 152
        Container:                              Container: 
            name = u'Emo' (total 3)                         name = u'Emo' (total 3)
            offset = 1569848 -> 1569936 88            |             offset = 1569552 -> 1569640 88
        Container:                              Container: 
            name = u'Funk1' (total 5)                           name = u'Funk1' (total 5)
            offset = 1558568 -> 1558736 168           |             offset = 1558280 -> 1558448 168
        Container:                              Container: 
            name = u'Funk2' (total 5)                           name = u'Funk2' (total 5)
            offset = 1558736 -> 1558904 168           |             offset = 1558448 -> 1558616 168
        Container:                              Container: 
            name = u'FunkRock' (total 8)                        name = u'FunkRock' (total 8)
            offset = 1559864 -> 1560016 152           |             offset = 1559576 -> 1559728 152
        Container:                              Container: 
            name = u'JazzFunk' (total 8)                        name = u'JazzFunk' (total 8)
            offset = 1560464 -> 1560896 432           |             offset = 1560176 -> 1560608 432
        Container:                              Container: 
            name = u'Motown' (total 6)                          name = u'Motown' (total 6)
            offset = 1560896 -> 1561184 288           |             offset = 1560608 -> 1560896 288
        Container:                              Container: 
            name = u'OneDrop' (total 7)                         name = u'OneDrop' (total 7)
            offset = 1571432 -> 1571576 144           |             offset = 1571136 -> 1571280 144
        Container:                              Container: 
            name = u'Steppers' (total 8)                        name = u'Steppers' (total 8)
            offset = 1565328 -> 1565432 104           |             offset = 1565032 -> 1565136 104
        Container:                              Container: 
            name = u'Rockers' (total 7)                         name = u'Rockers' (total 7)
            offset = 1570552 -> 1570640 88            |             offset = 1570256 -> 1570344 88
        Container:                              Container: 
            name = u'2nd Line' (total 8)                        name = u'2nd Line' (total 8)
            offset = 1562872 -> 1563000 128           |             offset = 1562584 -> 1562712 128
        Container:                              Container: 
            name = u'Country' (total 7)                         name = u'Country' (total 7)
            offset = 1559072 -> 1559240 168           |             offset = 1558784 -> 1558952 168
        Container:                              Container: 
            name = u'Blues1' (total 6)                          name = u'Blues1' (total 6)
            offset = 1571360 -> 1571432 72            |             offset = 1571064 -> 1571136 72
        Container:                              Container: 
            name = u'Blues2' (total 6)                          name = u'Blues2' (total 6)
            offset = 1561184 -> 1561320 136           |             offset = 1560896 -> 1561032 136
        Container:                              Container: 
            name = u'Jazz1' (total 5)                           name = u'Jazz1' (total 5)
            offset = 1575952 -> 1577048 1096              |             offset = 1575656 -> 1576720 1064
        Container:                              Container: 
            name = u'Jazz2' (total 5)                           name = u'Jazz2' (total 5)
            offset = 1573168 -> 1573224 56            |             offset = 1572872 -> 1572928 56
        Container:                              Container: 
            name = u'Bossa1' (total 6)                          name = u'Bossa1' (total 6)
            offset = 1569192 -> 1569288 96            |             offset = 1568896 -> 1568992 96
        Container:                              Container: 
            name = u'Bossa2' (total 6)                          name = u'Bossa2' (total 6)
            offset = 1569288 -> 1569576 288           |             offset = 1568992 -> 1569280 288
        Container:                              Container: 
            name = u'Samba1' (total 6)                          name = u'Samba1' (total 6)
            offset = 1558400 -> 1558568 168           |             offset = 1558112 -> 1558280 168
        Container:                              Container: 
            name = u'Samba2' (total 6)                          name = u'Samba2' (total 6)
            offset = 1557016 -> 1557376 360           |             offset = 1556728 -> 1557088 360
        Container:                              Container: 
            name = u'ROCKABLY' (total 8)                        name = u'ROCKABLY' (total 8)
            offset = 1571576 -> 1573168 1592              |             offset = 1571280 -> 1572872 1592
        Container:                              Container: 
            name = u"R'n'R" (total 5)                           name = u"R'n'R" (total 5)
            offset = 1564088 -> 1564432 344           |             offset = 1563800 -> 1564144 344
        Container:                              Container: 
            name = u'TomTomBt' (total 8)                        name = u'TomTomBt' (total 8)
            offset = 1561456 -> 1562744 1288              |             offset = 1561168 -> 1562456 1288
        Container:                              Container: 
            name = u'R&B1' (total 4)                            name = u'R&B1' (total 4)
            offset = 1556464 -> 1556832 368           |             offset = 1556176 -> 1556544 368
        Container:                              Container: 
            name = u'R&B2' (total 4)                            name = u'R&B2' (total 4)
            offset = 1562744 -> 1562872 128           |             offset = 1562456 -> 1562584 128
        Container:                              Container: 
            name = u'70s Soul' (total 8)                        name = u'70s Soul' (total 8)
            offset = 1560168 -> 1560320 152           |             offset = 1559880 -> 1560032 152
        Container:                              Container: 
            name = u'90s Soul' (total 8)                        name = u'90s Soul' (total 8)
            offset = 1563000 -> 1563608 608           |             offset = 1562712 -> 1563320 608
        Container:                              Container: 
            name = u'HipHop' (total 6)                          name = u'HipHop' (total 6)
            offset = 1560320 -> 1560464 144           |             offset = 1560032 -> 1560176 144
        Container:                              Container: 
            name = u'Disco' (total 5)                           name = u'Disco' (total 5)
            offset = 1557376 -> 1557552 176           |             offset = 1557088 -> 1557264 176
        Container:                              Container: 
            name = u'Pop' (total 3)                         name = u'Pop' (total 3)
            offset = 1558232 -> 1558400 168           |             offset = 1557944 -> 1558280 168
        Container:                              Container: 
            name = u'PopRock' (total 7)                         name = u'PopRock' (total 7)
            offset = 1556832 -> 1557016 184           |             offset = 1556544 -> 1556728 184
        Container:                              Container: 
            name = u'IndiePop' (total 8)                        name = u'IndiePop' (total 8)
            offset = 1563848 -> 1563968 120           |             offset = 1563560 -> 1563680 120
        Container:                              Container: 
            name = u'EuroPop' (total 7)                         name = u'EuroPop' (total 7)
            offset = 1570464 -> 1570552 88            |             offset = 1570168 -> 1570256 88
        Container:                              Container: 
            name = u'NewWave' (total 7)                         name = u'NewWave' (total 7)
            offset = 1554928 -> 1556464 1536 (first in list)  |             offset = 1554640 -> 1556176 1536 (first in list)
        Container:                              Container: 
            name = u'Ska' (total 3)                         name = u'Ska' (total 3)
            offset = 1570640 -> 1570640 88            |             offset = 1570344 -> 1570432 88
        Container:                              Container: 
            name = u'Shuffle1' (total 8)                        name = u'Shuffle1' (total 8)
            offset = 1565536 -> 1569192 3656              |             offset = 1565240 -> 1568896 3656
        Container:                              Container: 
            name = u'Shuffle2' (total 8)                        name = u'Shuffle2' (total 8)
            offset = 1558904 -> 1559072 168           |             offset = 1558616 -> 1558784 168
        Container:                              Container: 
            name = u'Fusion' (total 6)                          name = u'Fusion' (total 6)
            offset = 1561320 -> 1561456 136           |             offset = 1561032 -> 1561168 136
        Container:                              Container: 
            name = u'Swing1' (total 6)                          name = u'Swing1' (total 6)
            offset = 1570728 -> 1570816 88            |             offset = 1570432 -> 1570520 88
        Container:                              Container: 
            name = u'Swing2' (total 6)                          name = u'Swing2' (total 6)
            offset = 1569576 -> 1569848 272           |             offset = 1569280 -> 1569552 272
        Container:                              Container: 
            name = u'12/8 Tri' (total 8)                        name = u'12/8 Tri' (total 8)
            offset = 1559712 -> 1559864 152           |             offset = 1559424 -> 1559576 152
        Container:                              Container: 
            name = u'12/8 Grv' (total 8)                        name = u'12/8 Grv' (total 8)
            offset = 1559560 -> 1559712 152           |             offset = 1559272 -> 1559424 152
        Container:                              Container: 
            name = u'Waltz' (total 5)                           name = u'Waltz' (total 5)
            offset = 1573280 -> 1573720 440           |             offset = 1572984 -> 1573424 440
        Container:                              Container: 
            name = u'Breaks1' (total 7)                         name = u'Breaks1' (total 7)
            offset = 1565104 -> 1565216 112           |             offset = 1564704 -> 1564816 112
        Container:                              Container: 
            name = u'Breaks2' (total 7)                         name = u'Breaks2' (total 7)
            offset = 1563608 -> 1563728 120           |             offset = 1563320 -> 1563440 120
        Container:                              Container: 
            name = u'Breaks3' (total 7)                         name = u'Breaks3' (total 7)
            offset = 1565432 -> 1565536 104           |             offset = 1565136 -> 1565240 104
        Container:                              Container: 
            name = u'5/4 Grv' (total 7)                         name = u'5/4 Grv' (total 7)
            offset = 1570816 -> 1571360 544           |             offset = 1570520 -> 1571064 544
        Container:                              Container: 
            name = u'CtWaltz1' (total 8)                        name = u'CtWaltz1' (total 8)
            offset = 1575144 -> 1575952 808           |             offset = 1574848 -> 1575656 808
        Container:                              Container: 
            name = u'CtWaltz2' (total 8)                        name = u'CtWaltz2' (total 8)
            offset = 1573720 -> 1575144 1424              |             offset = 1573424 -> 1574848 1424
        Container:                              Container: 
            name = u'JzWaltz1' (total 8)                        name = u'JzWaltz1' (total 8)
            offset = 1577048 -> 1577392 344           |             offset = 1576720 -> 1577088 368
        Container:                              Container: 
            name = u'JzWaltz2' (total 8)                        name = u'JzWaltz2' (total 8)
            offset = 1573224 -> 1573280 56            |             offset = 1572928 -> 1572984 56
        Container:                              Container: 
            name = u'Metro3' (total 6)                          name = u'Metro3' (total 6)
            offset = 1578488 -> 1578832 344           |             offset = 1578112 -> 1578456 344
        Container:                              Container: 
            name = u'Metro4' (total 6)                          name = u'Metro4' (total 6)
            offset = 1577896 -> 1578488 592           |             offset = 1577568 -> 1578112 544
        Container:                              Container: 
            name = u'Metro5' (total 6)                          name = u'Metro5' (total 6)
            offset = 1577416 -> 1577896 480           |             offset = 1577112 -> 1577568 456
        Container:                              Container: 
            name = u'Metro' (total 5)                           name = u'Metro' (total 5)
            offset = 1578832 -> 1578848 16            |             offset = 1578456 -> 1578472 16
mungewell commented 4 years ago

So, re-arranging the pattern names/offsets into sequential order we can see that the first difference in the "pattern table" between v2.00 and v1.10 is at "Rock1" (seems that pattern data may have been tweaked/swapped).

This means that there is about 9Kbytes (out of ~490K) which in theory are duplicated between files, but maybe at different locations.... thinking this might be a good(?) way to figure out which data block is for the patterns, Not sure about the best way to do such a comparison....

big_chunk

mungewell commented 4 years ago

Ugh, spent way too much time staring into the abyss (aka hexdump of F/W).

Still don't see where a table of notes/timing might be stored, but I am 100% convinced it must be there somewhere... 3 bytes (in the table we found) is not enough space to encode enough information.

But agree that my earlier comment about 8KBytes seems to be way too much space (considering FW is only 46KByte in total. Since the drum pattern table is in FW (129 file) it makes sense that the note/pattern data is also there somewhere.

I took samples of each of the drum patterns, to see what they do and maybe re-create them. 'Metro' proves that they have some adjustment of sample level, others show they have (at least) 16th note resolution, and lots of patterns are pretty complex.

Another hook which might help is that Metro3, Metro4 and Metro5 are very simple. Just 'click' repeated on the whole note at same/full volume.

mungewell commented 4 years ago

Also '12/8 Tri' is in the FW table, but not listed in Manual or displayed by device... why? zoom_patterns

Anyone found a FW file for the A1Four/A1FourX? This apparently has a different set of drum patterns.

mungewell commented 4 years ago

Oh, so many questions. Looking at the 3rd data byte, what do these have in common?

$ python3 ../decode_patterns.py -d -O 407304 unzipped/.rsrc/1041/BIN/129  | grep -e name -e data3 | grep -B 1 '= 24' | grep name
            name = u'Dummy' (total 5)
            name = u'GUIDE' (total 5)
            name = u'Jazz1' (total 5)
            name = u'Jazz2' (total 5)
            name = u'Waltz' (total 5)
            name = u'CtWaltz1' (total 8)
            name = u'CtWaltz2' (total 8)
            name = u'JzWaltz1' (total 8)
            name = u'JzWaltz2' (total 8)
            name = u'Metro3' (total 6)
            name = u'Metro4' (total 6)
            name = u'Metro5' (total 6)
            name = u'Metro' (total 5)

Are they perhaps in a different area of memory?

Tomlinsky commented 4 years ago

Eyup munge. Bit busy to dive back into this at the moment but my pitch is that the Zoom's have simple 1 'pattern' tracker type players in them each of which would only need to comprise of a pointer to a few bytes of trigger deltas/sample Nos/Sample Volumes followed by a terminator.. This would be a very compact solution especially as no handling of pitch information is required. Each pattern would effectively a 'bar' in tracker world with each consisting of only a few tens bytes even in a complex drum pattern.