Digitech JamSync - How does it work?
Hi guys, I'm working on jamsync. First of all: "pz", thank you for your work.
English is not my primary language, I beg your pardon in advance for mistakes or incomprehensible sentences that I can write;-)
I have a JamMan Express Xt, it has only one big button to push. The guy at fuzzysynth has done a big work, but he owns a "JamMan Solo Xt" that allows to set BPM and others functions. With ExpressXt the BPM lacks of meaning, The only property of the loop is its lenght (ms, samples).
However, I want to share my experiences.
I've attached the minjack-to-din adapter cable from the OUT of Digitech to the MIDI IN of my Novation Impulse. It does not recognise any data (because 3.3v ?). Instead my Behringer BCR2000 can receive data, I think it is more tolerant with the voltage.
I've set a metronome to 90bpm and I've recorded some loop of differents lenght.
I've found changing and fixed values:
F0 00 00 10 7F 62 01 v1 01 v2 v3 v4 v5 02 04 v6 03 v7 v8 v9 w1 w2 w3 F7
values v(x) and w(x) change
v1 ( byte 8 ) : 42, 4A but I've found also 5A,62
w2 is the "command"
02, restart loop after a stop
04, stop
05, loop running
06, initial play
w1 is the most significant byte of the lenght ( I think)
3F, half measure (2/4)
40, 1 or 2 measures (4/4 or 8/4)
41, 4 measure (16/4)
42, about a minute
with Sekaiju (a midi sequencer) I am able to send back the data to ExpressXt.
I've put on track 1 the sync stream made of 11 bytes. It keeps active the "link". If this signal feeds too slow, every one of them restart the link and the ExpressXt flashes its leds again and again.
On track 2 I've put some midi note on for trigger drum sound, useful to play over.
On track 3 I've put "arbitrary sysex" message, with the 24 bytes chunk. With random values v(x),w(x) but command w2 properly set are not recognized, ExpressXt does not react.
Instead the 24 bytes chunk created by ExpressXt, previously read, works. Using a chunk of an audio loop longer than the "midi" loop almost works:
ex.
F0 00 00 10 7F 62 01 5A 01 1D 44 33 42 02 04 78 03 05 63 2A 40 05 07 F7
You have to record the full lenght, but then it restart in sync every time that the command is issued.
If you force stop manually the recording of the loop, then it is not linked and it is out of sync.
I hope that my experiences can help someone else and we all can improve the knowledge of the protocol and figure out something else.
Rgds,
Calde
English is not my primary language, I beg your pardon in advance for mistakes or incomprehensible sentences that I can write;-)
I have a JamMan Express Xt, it has only one big button to push. The guy at fuzzysynth has done a big work, but he owns a "JamMan Solo Xt" that allows to set BPM and others functions. With ExpressXt the BPM lacks of meaning, The only property of the loop is its lenght (ms, samples).
However, I want to share my experiences.
I've attached the minjack-to-din adapter cable from the OUT of Digitech to the MIDI IN of my Novation Impulse. It does not recognise any data (because 3.3v ?). Instead my Behringer BCR2000 can receive data, I think it is more tolerant with the voltage.
I've set a metronome to 90bpm and I've recorded some loop of differents lenght.
I've found changing and fixed values:
F0 00 00 10 7F 62 01 v1 01 v2 v3 v4 v5 02 04 v6 03 v7 v8 v9 w1 w2 w3 F7
values v(x) and w(x) change
v1 ( byte 8 ) : 42, 4A but I've found also 5A,62
w2 is the "command"
02, restart loop after a stop
04, stop
05, loop running
06, initial play
w1 is the most significant byte of the lenght ( I think)
3F, half measure (2/4)
40, 1 or 2 measures (4/4 or 8/4)
41, 4 measure (16/4)
42, about a minute
with Sekaiju (a midi sequencer) I am able to send back the data to ExpressXt.
I've put on track 1 the sync stream made of 11 bytes. It keeps active the "link". If this signal feeds too slow, every one of them restart the link and the ExpressXt flashes its leds again and again.
On track 2 I've put some midi note on for trigger drum sound, useful to play over.
On track 3 I've put "arbitrary sysex" message, with the 24 bytes chunk. With random values v(x),w(x) but command w2 properly set are not recognized, ExpressXt does not react.
Instead the 24 bytes chunk created by ExpressXt, previously read, works. Using a chunk of an audio loop longer than the "midi" loop almost works:
ex.
F0 00 00 10 7F 62 01 5A 01 1D 44 33 42 02 04 78 03 05 63 2A 40 05 07 F7
You have to record the full lenght, but then it restart in sync every time that the command is issued.
If you force stop manually the recording of the loop, then it is not linked and it is out of sync.
I hope that my experiences can help someone else and we all can improve the knowledge of the protocol and figure out something else.
Rgds,
Calde
Bit 23 is a checksum value:
JamSync calculate it how a BitXor of the bytes 8, 9, .... 21, 22
for example in the following 24 bytes sysex message:
F0 00 00 10 7F 62 01 7A 01 4D 42 30 42 02 04 50 03 47 4B 2D 40 05 37 F7
the byte number 23, hex value 37 (dec 55) is calculated as Bit Xor of the bytes from 8 to 22
-- -- -- -- -- -- -- 7A 01 4D 42 30 42 02 04 50 03 47 4B 2D 40 05 -- --
This works for every sysex message that I've tried.
I've test with OpenOffice macro:
Function BitXOR( val1 , val2 )
BitXOR = val1 XOR val2
End Function
JamSync calculate it how a BitXor of the bytes 8, 9, .... 21, 22
for example in the following 24 bytes sysex message:
F0 00 00 10 7F 62 01 7A 01 4D 42 30 42 02 04 50 03 47 4B 2D 40 05 37 F7
the byte number 23, hex value 37 (dec 55) is calculated as Bit Xor of the bytes from 8 to 22
-- -- -- -- -- -- -- 7A 01 4D 42 30 42 02 04 50 03 47 4B 2D 40 05 -- --
This works for every sysex message that I've tried.
I've test with OpenOffice macro:
Function BitXOR( val1 , val2 )
BitXOR = val1 XOR val2
End Function
Hi! Glad someone is working on this. I've done some work on it before but I got tired of it eventually.
Here is some data I got from the jamsync output, might be useful for some:
Here is some data I got from the jamsync output, might be useful for some:
Code: Select all
(F0, 0, 0, 10, 7F, 62, 1, 4A, 1, 11, 62, 3B, 42, 2, 4, 58, 3, 36, 71, 23, 40, 5, 3D, F7, ) // BPM: 50, loop lenght: 4800
(F0, 0, 0, 10, 7F, 62, 1, 6A, 1, 56, 7B, 43, 42, 2, 4, 48, 3, C, 26, 1D, 40, 5, 78, F7, ) // BPM: 52, loop lenght: 4615
(F0, 0, 0, 10, 7F, 62, 1, 6A, 1, 53, 31, 4B, 42, 2, 4, 48, 3, 63, 2F, 17, 40, 5, 53, F7, ) // BPM: 54, loop lenght: 4444
(F0, 0, 0, 10, 7F, 62, 1, 7A, 1, 34, 77, 52, 42, 2, 4, 58, 3, 62, 1D, 11, 40, 5, 5E, F7, ) // BPM: 56, loop lenght: 4285
(F0, 0, 0, 10, 7F, 62, 1, 7A, 1, 78, 72, 5A, 42, 2, 4, 48, 3, 7D, 4E, C, 40, 5, 5E, F7, ) // BPM: 58, loop lenght: 4137
(F0, 0, 0, 10, 7F, 62, 1, 7A, 1, 21, 49, 62, 42, 2, 4, 48, 3, 7, 75, 7, 40, 5, 4E, F7, ) // BPM: 60, loop lenght: 4000
(F0, 0, 0, 10, 7F, 62, 1, 6A, 1, 11, 76, 6A, 42, 2, 4, 68, 3, 51, 5, 3, 40, 5, 5B, F7, ) // BPM: 62, loop lenght: 3870
(F0, 0, 0, 10, 7F, 62, 1, 4A, 1, 38, 62, 72, 42, 2, 4, 60, 3, 1, 7B, 7D, 40, 5, 6, F7, ) // BPM: 64, loop lenght: 3750
(F0, 0, 0, 10, 7F, 62, 1, 4A, 1, 47, 30, 7A, 42, 2, 4, 50, 3, 23, 13, 75, 40, 5, 51, F7, ) // BPM: 66, loop lenght: 3636
(F0, 0, 0, 10, 7F, 62, 1, 62, 1, 6F, 4, 1, 43, 2, 4, 60, 3, 1E, 1A, 6E, 40, 5, 0, F7, ) // BPM: 68, loop lenght: 3529
(F0, 0, 0, 10, 7F, 62, 1, 72, 1, 21, 58, 4, 43, 2, 4, 60, 3, 2D, 3E, 67, 40, 5, 19, F7, ) // BPM: 70, loop lenght: 3428
(F0, 0, 0, 10, 7F, 62, 1, 72, 1, 44, 53, 8, 43, 2, 4, 50, 3, 4A, 4, 60, 40, 5, 11, F7, ) // BPM: 72, loop lenght: 3333
(F0, 0, 0, 10, 7F, 62, 1, 52, 1, 5C, 3E, C, 43, 2, 4, 60, 3, 6E, 44, 5A, 40, 5, 2E, F7, ) // BPM: 74, loop lenght: 3243
(F0, 0, 0, 10, 7F, 62, 1, 72, 1, D, 8, 10, 43, 2, 4, 70, 3, 48, B, 54, 40, 5, 2, F7, ) // BPM: 76, loop lenght: 3157
(F0, 0, 0, 10, 7F, 62, 1, 5A, 1, 70, 8, 14, 42, 2, 4, 70, 3, 22, 52, 4E, 40, 5, 7B, F7, ) // BPM: 78, loop lenght: 3076
(F0, 0, 0, 10, 7F, 62, 1, 5A, 1, 38, 7, 18, 42, 2, 4, 60, 3, 47, 67, 49, 40, 5, 77, F7, ) // BPM: 80, loop lenght: 3000
(F0, 0, 0, 10, 7F, 62, 1, 4A, 1, 4C, 65, 1C, 42, 2, 4, 60, 3, 43, 6C, 44, 40, 5, 77, F7, ) // BPM: 82, loop lenght: 2926
(F0, 0, 0, 10, 7F, 62, 1, 4A, 1, 25, 64, 20, 42, 2, 4, 50, 3, 1E, 8, 3F, 40, 5, 51, F7, ) // BPM: 84, loop lenght: 2857
(F0, 0, 0, 10, 7F, 62, 1, 7A, 1, 45, E, 24, 42, 2, 4, 70, 3, 28, 2E, 3A, 40, 5, 5A, F7, ) // BPM: 86, loop lenght: 2790
(F0, 0, 0, 10, 7F, 62, 1, 4A, 1, 58, 42, 28, 42, 2, 4, 50, 3, 54, 13, 36, 40, 5, 5A, F7, ) // BPM: 88, loop lenght: 2727
(F0, 0, 0, 10, 7F, 62, 1, 4A, 1, 31, 1, 2C, 42, 2, 4, 70, 3, E, 19, 32, 40, 5, 0, F7, ) // BPM: 90, loop lenght: 2666
(F0, 0, 0, 10, 7F, 62, 1, 5A, 1, 6F, 60, 2F, 42, 2, 4, 70, 3, 77, 2A, 2E, 40, 5, 7A, F7, ) // BPM: 92, loop lenght: 2608
(F0, 0, 0, 10, 7F, 62, 1, 7A, 1, C, 61, 33, 42, 2, 4, 70, 3, F, 47, 2A, 40, 5, 35, F7, ) // BPM: 94, loop lenght: 2553
(F0, 0, 0, 10, 7F, 62, 1, 5A, 1, 74, 6D, 37, 42, 2, 4, 60, 3, 35, 5, 27, 40, 5, 0, F7, ) // BPM: 96, loop lenght: 2500
(F0, 0, 0, 10, 7F, 62, 1, 7A, 1, 2A, 1B, 3B, 42, 2, 4, 70, 3, 62, 3E, 23, 40, 5, 7C, F7, ) // BPM: 98, loop lenght: 2448
(F0, 0, 0, 10, 7F, 62, 1, 5A, 1, E, B, 3F, 42, 2, 4, 60, 3, 30, 61, 20, 40, 5, 72, F7, ) // BPM: 100, loop lenght: 2400
(F0, 0, 0, 10, 7F, 62, 1, 5A, 1, 7F, 41, 43, 42, 2, 4, 50, 3, 20, 6E, 1C, 40, 5, 26, F7, ) // BPM: 102, loop lenght: 2352
(F0, 0, 0, 10, 7F, 62, 1, 7A, 1, 0, 8, 47, 42, 2, 4, 70, 3, 17, 75, 19, 40, 5, 3D, F7, ) // BPM: 106, loop lenght: 2264
(F0, 0, 0, 10, 7F, 62, 1, 4A, 1, 68, 1D, 4F, 42, 2, 4, 60, 3, 50, 52, 14, 40, 5, 5, F7, ) // BPM: 108, loop lenght: 2222
(F0, 0, 0, 10, 7F, 62, 1, 6A, 1, 6A, 7, 53, 42, 2, 4, 50, 3, 33, 12, 11, 40, 5, 37, F7, ) // BPM: 110, loop lenght: 2181
(F0, 0, 0, 10, 7F, 62, 1, 6A, 1, 69, 29, 57, 42, 2, 4, 50, 3, 67, 46, E, 40, 5, 1, F7, ) // BPM: 112, loop lenght: 2142
(F0, 0, 0, 10, 7F, 62, 1, 7A, 1, 32, 7B, 5A, 42, 2, 4, 60, 3, 65, 48, C, 40, 5, 2B, F7, ) // BPM: 114, loop lenght: 2105
(F0, 0, 0, 10, 7F, 62, 1, 7A, 1, 3B, 5E, 5E, 42, 2, 4, 70, 3, 12, 56, 9, 40, 5, 7F, F7, ) // BPM: 116, loop lenght: 2068
(F0, 0, 0, 10, 7F, 62, 1, 5A, 1, 7B, 78, 62, 42, 2, 4, 40, 3, 11, 59, 7, 40, 5, 37, F7, ) // BPM: 118, loop lenght: 2033
(F0, 0, 0, 10, 7F, 62, 1, 7A, 1, 53, 6B, 66, 42, 2, 4, 40, 3, 4C, 8, 5, 40, 5, 26, F7, ) // BPM: 120, loop lenght: 2000
(F0, 0, 0, 10, 7F, 62, 1, 7A, 1, 3B, 46, 6A, 42, 2, 4, 50, 3, 14, 59, 2, 40, 5, 71, F7, ) // BPM: 122, loop lenght: 1967
(F0, 0, 0, 10, 7F, 62, 1, 4A, 1, 3F, 70, 6E, 42, 2, 4, 70, 3, 19, 56, 0, 40, 5, 57, F7, ) // BPM: 124, loop lenght: 1935
(F0, 0, 0, 10, 7F, 62, 1, 5A, 1, 6, D, 72, 42, 2, 4, 68, 3, 44, 4E, 7D, 3F, 5, 40, F7, ) // BPM: 126, loop lenght: 1904
(F0, 0, 0, 10, 7F, 62, 1, 4A, 1, 2D, 76, 76, 42, 2, 4, 68, 3, 4F, 49, 79, 3F, 5, C, F7, ) // BPM: 128, loop lenght: 1875
(F0, 0, 0, 10, 7F, 62, 1, 6A, 1, 15, 1D, 7D, 42, 2, 4, 58, 3, 28, 3C, 72, 3F, 5, 5D, F7, ) // BPM: 130, loop lenght: 1846
(F0, 0, 0, 10, 7F, 62, 1, 4A, 1, 3C, 4E, 7E, 42, 2, 4, 58, 3, 5D, 19, 71, 3F, 5, 57, F7, ) // BPM: 132, loop lenght: 1818
(F0, 0, 0, 10, 7F, 62, 1, 62, 1, 6F, 4, 1, 43, 2, 4, 68, 3, 1E, 1A, 6E, 3F, 5, 77, F7, ) // BPM: 134, loop lenght: 1791
(F0, 0, 0, 10, 7F, 62, 1, 62, 1, 79, 9, 3, 43, 2, 4, 48, 3, 22, 6F, 6A, 3F, 5, 3, F7, ) // BPM: 136, loop lenght: 1764
(F0, 0, 0, 10, 7F, 62, 1, 42, 1, 2E, 46, 7, 43, 2, 4, 48, 3, 2A, 18, 63, 3F, 5, 49, F7, ) // BPM: 138, loop lenght: 1739
(F0, 0, 0, 10, 7F, 62, 1, 52, 1, 29, 69, 6, 43, 2, 4, 78, 3, 3F, 34, 63, 3F, 5, 79, F7, ) // BPM: 140, loop lenght: 1714
(F0, 0, 0, 10, 7F, 62, 1, 42, 1, 37, 11, 9, 43, 2, 4, 68, 3, 21, 1F, 60, 3F, 5, 26, F7, ) // BPM: 142, loop lenght: 1690
(F0, 0, 0, 10, 7F, 62, 1, 72, 1, 2, 4C, A, 43, 2, 4, 68, 3, 55, 53, 5D, 3F, 5, 78, F7, ) // BPM: 144, loop lenght: 1666
(F0, 0, 0, 10, 7F, 62, 1, 52, 1, 3B, 5B, C, 43, 2, 4, 48, 3, 31, 18, 5A, 3F, 5, 78, F7, ) // BPM: 146, loop lenght: 1643
(F0, 0, 0, 10, 7F, 62, 1, 52, 1, 35, 4D, E, 43, 2, 4, 68, 3, 28, 1F, 57, 3F, 5, 51, F7, ) // BPM: 148, loop lenght: 1621
(F0, 0, 0, 10, 7F, 62, 1, 52, 1, 62, 1F, 10, 43, 2, 4, 48, 3, 3B, 6A, 54, 3F, 5, F, F7, ) // BPM: 150, loop lenght: 1600
(F0, 0, 0, 10, 7F, 62, 1, 72, 1, 64, 4B, 12, 43, 2, 4, 68, 3, 75, 44, 51, 3F, 5, 3A, F7, ) // BPM: 152, loop lenght: 1578
(F0, 0, 0, 10, 7F, 62, 1, 72, 1, 4D, 48, 14, 43, 2, 4, 48, 3, 29, 79, 4E, 3F, 5, 48, F7, ) // BPM: 154, loop lenght: 1558
(F0, 0, 0, 10, 7F, 62, 1, 72, 1, 16, 32, 16, 43, 2, 4, 58, 3, 1A, 5A, 4B, 3F, 5, 6E, F7, ) // BPM: 156, loop lenght: 1538
(F0, 0, 0, 10, 7F, 62, 1, 52, 1, 1B, 5C, 18, 43, 2, 4, 78, 3, 6F, 77, 48, 3F, 5, 58, F7, ) // BPM: 158, loop lenght: 1518
(F0, 0, 0, 10, 7F, 62, 1, 42, 1, 61, 67, 1A, 43, 2, 4, 58, 3, 74, 75, 46, 3F, 5, 3C, F7, ) // BPM: 160, loop lenght: 1500
(F0, 0, 0, 10, 7F, 62, 1, 72, 1, 4C, 1A, 1C, 43, 2, 4, 68, 3, 28, 29, 44, 3F, 5, 68, F7, ) // BPM: 162, loop lenght: 1481
(F0, 0, 0, 10, 7F, 62, 1, 62, 1, A, 70, 1E, 43, 2, 4, 58, 3, 12, 64, 41, 3F, 5, 14, F7, ) // BPM: 164, loop lenght: 1463
(F0, 0, 0, 10, 7F, 62, 1, 72, 1, 25, 9, 20, 43, 2, 4, 48, 3, 61, 5B, 3F, 3F, 5, 4E, F7, ) // BPM: 166, loop lenght: 1445
(F0, 0, 0, 10, 7F, 62, 1, 72, 1, 66, 1D, 22, 43, 2, 4, 58, 3, F, 69, 3C, 3F, 5, 54, F7, ) // BPM: 168, loop lenght: 1428
(F0, 0, 0, 10, 7F, 62, 1, 62, 1, 8, 5D, 24, 43, 2, 4, 78, 3, 14, 66, 3A, 3F, 5, 5E, F7, ) // BPM: 170, loop lenght: 1411
(F0, 0, 0, 10, 7F, 62, 1, 42, 1, 2, 3B, 26, 43, 2, 4, 78, 3, 3B, 4D, 38, 3F, 5, 16, F7, ) // BPM: 172, loop lenght: 1395
(F0, 0, 0, 10, 7F, 62, 1, 62, 1, 71, 75, 28, 43, 2, 4, 48, 3, 68, 5B, 36, 3F, 5, 7E, F7, ) // BPM: 174, loop lenght: 1379
(F0, 0, 0, 10, 7F, 62, 1, 62, 1, 3, 56, 2A, 43, 2, 4, 68, 3, 6E, 58, 34, 3F, 5, A, F7, ) // BPM: 176, loop lenght: 1363
(F0, 0, 0, 10, 7F, 62, 1, 72, 1, 28, 6B, 2B, 43, 2, 4, 78, 3, 6D, 2F, 32, 3F, 5, 6F, F7, ) // BPM: 178, loop lenght: 1348
(F0, 0, 0, 10, 7F, 62, 1, 42, 1, 5B, C, 2E, 43, 2, 4, 78, 3, 35, 0, 30, 3F, 5, 3B, F7, ) // BPM: 180, loop lenght: 1333
(F0, 0, 0, 10, 7F, 62, 1, 42, 1, 1B, 24, 30, 43, 2, 4, 68, 3, 5C, 67, 2E, 3F, 5, 4D, F7, ) // BPM: 182, loop lenght: 1318
(F0, 0, 0, 10, 7F, 62, 1, 62, 1, 42, 31, 32, 43, 2, 4, 48, 3, 61, 65, 2C, 3F, 5, 3E, F7, ) // BPM: 184, loop lenght: 1304
(F0, 0, 0, 10, 7F, 62, 1, 62, 1, 6, 1C, 34, 43, 2, 4, 78, 3, 23, F, 2A, 3F, 5, 4F, F7, ) // BPM: 186, loop lenght: 1290
(F0, 0, 0, 10, 7F, 62, 1, 42, 1, 4A, 42, 36, 43, 2, 4, 58, 3, 29, D, 28, 3F, 5, 55, F7, ) // BPM: 188, loop lenght: 1276
(F0, 0, 0, 10, 7F, 62, 1, 72, 1, 45, 79, 37, 43, 2, 4, 78, 3, 6, 7A, 26, 3F, 5, 26, F7, ) // BPM: 190, loop lenght: 1263
(F0, 0, 0, 10, 7F, 62, 1, 72, 1, 3D, 52, 39, 43, 2, 4, 68, 3, 5, 51, 25, 3F, 5, 40, F7, ) // BPM: 192, loop lenght: 1250
(F0, 0, 0, 10, 7F, 62, 1, 72, 1, 2C, 68, 3B, 43, 2, 4, 68, 3, 47, 7B, 23, 3F, 5, 7, F7, ) // BPM: 194, loop lenght: 1237
(F0, 0, 0, 10, 7F, 62, 1, 72, 1, 76, 3B, 3D, 43, 2, 4, 58, 3, 24, 69, 21, 3F, 5, 4B, F7, ) // BPM: 196, loop lenght: 1224
(F0, 0, 0, 10, 7F, 62, 1, 62, 1, 11, 3, 40, 43, 2, 4, 58, 3, 7, 7D, 1F, 3F, 5, 70, F7, ) // BPM: 198, loop lenght: 1212
(F0, 0, 0, 10, 7F, 62, 1, 72, 1, 16, 19, 41, 43, 2, 4, 78, 3, 0, 2D, 1E, 3F, 5, A, F7, ) // BPM: 200, loop lenght: 1200
Hi ashimoke, your data is definitely useful.
As I've the express xt, I can't be precise with my data.
I've already got some formulas to/from the ysex string to BMP and loop lenght, now I can verify them against your table.
Loop lenght => what is the Unit Of Measure? (ms; milliseconds)
Enrico
As I've the express xt, I can't be precise with my data.
I've already got some formulas to/from the ysex string to BMP and loop lenght, now I can verify them against your table.
Loop lenght => what is the Unit Of Measure? (ms; milliseconds)
Enrico
I've done some tests and it seems to work. Perhaps someone can try it for testing and improve it.
Code: Select all
#include <math.h>
/*
* THANKS TO
* @ https://www.freestompboxes.org/viewtopic.php?f=1&t=26184
* to the user pz to have starting all
* to the user smithoid to initial analysis
* to the user ashimoke for sharing his data and support
* @ http://fuzzysynth.blogspot.it/2015/06/digitech-jam-man.html
* to fuzzy music for sharing the work on protocol
* @ http://chemiker1981.blogspot.it/2010/10/1-reading-midi-clock-to-read-midi-clock.html
* to chemiker1981 for midi clock code
*
* r0 - initial release for testing
*/
// MIDI STATUS BYTES
byte midi_start = 0xfa;
byte midi_stop = 0xfc;
byte midi_clock = 0xf8;
byte midi_continue = 0xfb;
// INTERNALS
byte play_flag = 0;
byte incoming_data;
// DATA FOR CALCULATIONS
unsigned int QPM = 4; // QUARTERS PER MEASURE
unsigned int NOM = 1; // MINIMUM NUMBERS OF MEASURE OF THE LOOP
unsigned int PPQ = 24; // TICK OR PULSES PER QUARTER
unsigned int BPM = 0; // BEATS PER MINUTE
// TIMINGS AND COUNTERS
unsigned int Tick_Counter = 0;
unsigned long jamsync_measure_timer;
unsigned long jamsync_link_timer ;
// SYSEX ARRAYS
unsigned int jamsync_sync[] {0x00,0xF0,0x00,0x00,0x10,0x7F,0x62,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x04,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xF7};
unsigned int jamsync_link[] {0x00,0xF0,0x00,0x00,0x10,0x7F,0x62,0x01,0x00,0x01,0x01,0xF7};
unsigned int jamsync_stop[] {0x00,0xF0,0x00,0x00,0x10,0x7F,0x62,0x01,0x4A,0x01,0x04,0x46,0x30,0x42,0x02,0x04,0x40,0x03,0x4E,0x46,0x2E,0x40,0x04,0x5C,0xF7};
void setup() {
Serial.begin(31250);
jamsync_link_timer = micros();
}
void loop() {
// READ THE INCOMING MIDI
CheckSerial();
// KEEP LINK ACTIVE
if (micros() - jamsync_link_timer > 400000) {sendLink();}
// SEND SYNC COMMAND
if (Tick_Counter == NOM*QPM*PPQ) {
GetBPM();
Sendjamsync_sync();
Tick_Counter = 0;
}
}
void CheckSerial() {
if(Serial.available() > 0) {
incoming_data = Serial.read();
if(incoming_data == midi_start) {
play_flag = 1;
if (BPM > 0) {Sendjamsync_sync();}
jamsync_measure_timer = micros();
Tick_Counter = 0;
}
else if(incoming_data == midi_continue) {
play_flag = 1;
}
else if(incoming_data == midi_stop) {
play_flag = 0;
sendStop();
}
else if((incoming_data == midi_clock) && (play_flag == 1)) {
Tick_Counter++;
}
}
}
void sendLink() {
for (int i = 1; i < 12; i++) { Serial.write(jamsync_link[i]); }
jamsync_link_timer = micros();
}
void sendStop() {
for (int i = 1; i < 25; i++) { Serial.write(jamsync_stop[i]); }
}
void GetBPM() {
jamsync_measure_timer = micros() - jamsync_measure_timer;
BPM = QPM * 60000000 / jamsync_measure_timer;
jamsync_measure_timer = micros();
}
void Sendjamsync_sync(){
unsigned long LoopTime;
int b163 = 0;
int w;
int x;
int y;
int z=0; //xor checksum
LoopTime = floor(1000* NOM * QPM * 60.0 / BPM);
x = floor(log(LoopTime/2000.0)/log(4.0));
b163 = (LoopTime/(2000.0 * pow(4.0,x)))>2;
y = 2 * pow(2,b163) * pow(4,x);
w = floor(LoopTime / y);
// BPM
jamsync_sync[8] = 66 + 8 * ((63<BPM) && (BPM<128) || BPM>191) ;
jamsync_sync[12] = (4*BPM>127 && 4*BPM<256)*(4*BPM-128) +
(2*BPM>127 && 2*BPM<256)*(2*BPM -128) +
(BPM>127 && BPM<256)*(BPM-128);
jamsync_sync[13] = 1*(BPM>127)+66;
// lenght
jamsync_sync[16] = 64 + 8*b163;
jamsync_sync[21] = 64 + x;
jamsync_sync[20] = 128 *(0.001*w-1);
jamsync_sync[19] = pow(128.0,2) *(0.001*w-1 - jamsync_sync[20]/128.0);
jamsync_sync[18] = pow(128.0,3) *(0.001*w-1 - jamsync_sync[20]/128.0 - jamsync_sync[19]/pow(128.0,2));
// command
jamsync_sync[22] = 5;
// checksum
for (int i = 8; i < 23; i++) {
z = z ^ int(jamsync_sync[i]); // checksum XOR
}
jamsync_sync[23] = z;
for (int i = 1; i < 25; i++) {
Serial.write(int(jamsync_sync[i]));
}
}
r1, fix LoopTime lenght to improve the sync of 1st loop.
Code: Select all
#include <math.h>
/*
* THANKS TO
* @ https://www.freestompboxes.org/viewtopic.php?f=1&t=26184
* to the user pz to have starting all
* to the user smithoid to initial analysis
* to the user ashimoke for sharing his data and support
* @ http://fuzzysynth.blogspot.it/2015/06/digitech-jam-man.html
* to fuzzy music for sharing the work on protocol
* @ http://chemiker1981.blogspot.it/2010/10/1-reading-midi-clock-to-read-midi-clock.html
* to chemiker1981 for midi clock code
*
* r0 - initial release for testing
* r1 - LoopTime = effective lenght
*/
// MIDI STATUS BYTES
byte midi_start = 0xfa;
byte midi_stop = 0xfc;
byte midi_clock = 0xf8;
byte midi_continue = 0xfb;
// INTERNALS
byte play_flag = 0;
byte incoming_data;
// DATA FOR CALCULATIONS
unsigned int QPM = 4; // QUARTERS PER MEASURE
unsigned int NOM = 1; // MINIMUM NUMBERS OF MEASURE OF THE LOOP
unsigned int PPQ = 24; // TICK OR PULSES PER QUARTER
unsigned int BPM = 0; // BEATS PER MINUTE
// TIMINGS AND COUNTERS
unsigned int Tick_Counter = 0;
unsigned long jamsync_measure_timer;
unsigned long jamsync_loop_timer;
unsigned long jamsync_link_timer ;
// SYSEX ARRAYS
unsigned int jamsync_sync[] {0x00,0xF0,0x00,0x00,0x10,0x7F,0x62,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x04,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xF7};
unsigned int jamsync_link[] {0x00,0xF0,0x00,0x00,0x10,0x7F,0x62,0x01,0x00,0x01,0x01,0xF7};
unsigned int jamsync_stop[] {0x00,0xF0,0x00,0x00,0x10,0x7F,0x62,0x01,0x4A,0x01,0x04,0x46,0x30,0x42,0x02,0x04,0x40,0x03,0x4E,0x46,0x2E,0x40,0x04,0x5C,0xF7};
void setup() {
Serial.begin(31250);
jamsync_link_timer = micros();
}
void loop() {
// READ THE INCOMING MIDI
CheckSerial();
// KEEP LINK ACTIVE
if (micros() - jamsync_link_timer > 400000) {sendLink();}
// SEND SYNC COMMAND
if (Tick_Counter == NOM*QPM*PPQ) {
GetBPM();
Sendjamsync_sync();
Tick_Counter = 0;
}
}
void CheckSerial() {
if(Serial.available() > 0) {
incoming_data = Serial.read();
if(incoming_data == midi_start) {
play_flag = 1;
if (BPM > 0) {Sendjamsync_sync();}
jamsync_measure_timer = micros();
Tick_Counter = 0;
}
else if(incoming_data == midi_continue) {
play_flag = 1;
}
else if(incoming_data == midi_stop) {
play_flag = 0;
sendStop();
}
else if((incoming_data == midi_clock) && (play_flag == 1)) {
Tick_Counter++;
}
}
}
void sendLink() {
for (int i = 1; i < 12; i++) { Serial.write(jamsync_link[i]); }
jamsync_link_timer = micros();
}
void sendStop() {
for (int i = 1; i < 25; i++) { Serial.write(jamsync_stop[i]); }
}
void GetBPM() {
jamsync_measure_timer = micros() - jamsync_measure_timer;
jamsync_loop_timer = jamsync_measure_timer;
BPM = round(QPM * 60000000.0 / jamsync_measure_timer);
jamsync_measure_timer = micros();
}
void Sendjamsync_sync(){
unsigned long LoopTime;
int b163 = 0;
int w;
int x;
int y;
int z=0; //xor checksum
// LoopTime = floor(1000* NOM * QPM * 60.0 / BPM);
LoopTime = floor(jamsync_loop_timer / 1000.0);
x = floor(log(LoopTime/2000.0)/log(4.0));
b163 = (LoopTime/(2000.0 * pow(4.0,x)))>2;
y = 2 * pow(2,b163) * pow(4,x);
w = floor(LoopTime / y);
// BPM
jamsync_sync[8] = 66 + 8 * ((63<BPM) && (BPM<128) || BPM>191) ;
jamsync_sync[12] = (4*BPM>127 && 4*BPM<256)*(4*BPM-128) +
(2*BPM>127 && 2*BPM<256)*(2*BPM -128) +
(BPM>127 && BPM<256)*(BPM-128);
jamsync_sync[13] = 1*(BPM>127)+66;
// lenght
jamsync_sync[16] = 64 + 8*b163;
jamsync_sync[21] = 64 + x;
jamsync_sync[20] = 128 *(0.001*w-1);
jamsync_sync[19] = pow(128.0,2) *(0.001*w-1 - jamsync_sync[20]/128.0);
jamsync_sync[18] = pow(128.0,3) *(0.001*w-1 - jamsync_sync[20]/128.0 - jamsync_sync[19]/pow(128.0,2));
// command
jamsync_sync[22] = 5;
// checksum
for (int i = 8; i < 23; i++) {
z = z ^ int(jamsync_sync[i]); // checksum XOR
}
jamsync_sync[23] = z;
for (int i = 1; i < 25; i++) {
Serial.write(int(jamsync_sync[i]));
}
}
When I got Calde's code working I was thinking about permanent instalation of the arduino sync box and decided to make it internal. I used arduino nano and placed it in the battery compartment — I never use batteries with this pedal so it was an easy decision. I unsoldered the Sync in jack and put panel mounted 3,5mm for midi input. There is a on/off toggle switch so the pedal can be used standalone.
It also got a new knob and paintjob. Which I don't like that much now, will work on that some more.
It also got a new knob and paintjob. Which I don't like that much now, will work on that some more.
Hey Ashimoke, great work! I'm happy that my code works well for you. Congrats for the vintage layout.
If someone wants to try, I've used the following schematics https://www.olimex.com/Products/Duino/S ... DI-sch.pdf without the analog inputs and leds.
tips: When jamsync and an arduino running my code are properly connected, jamsync flashes both 1st and 3rd led three times, to show an active working link.
If someone wants to try, I've used the following schematics https://www.olimex.com/Products/Duino/S ... DI-sch.pdf without the analog inputs and leds.
tips: When jamsync and an arduino running my code are properly connected, jamsync flashes both 1st and 3rd led three times, to show an active working link.
Information
- Posts: 4
- Joined: 05 Nov 2015, 09:03
Hey all, I have a jamman express solo xt I'd like to set to loop exactly to tempo to be in time with a drum machine. Where's the best place for me to start reading to understand all that you've been talking about. Thanks.
hi.Chris, all you need is in this topic, including the link for the work of fuzzysynth. I have not found other useful informations elsewhere.
the posts from the user 'pz' explain how to connect a midi cable to the jamman. After you need an arduino (uno for example) and a midi shield (buy or diy). Finally you can upload my sketch in to the arduino, connect the midi out to the jamsync in port, the midi in to the midi out of the drummachine.
I have tested succesfully with a korg electribe er1. Every device that sends midiclock data should work.
My sketch analyzes the duration of the first measure and then it starts to sync the jamman to every measure (or a multiple of...) on the midi stream.
User Ashimoke offers a solution for mounting the arduino inside the jamman.
do everything at you risk, a wrong connection can damage your devices.
the posts from the user 'pz' explain how to connect a midi cable to the jamman. After you need an arduino (uno for example) and a midi shield (buy or diy). Finally you can upload my sketch in to the arduino, connect the midi out to the jamsync in port, the midi in to the midi out of the drummachine.
I have tested succesfully with a korg electribe er1. Every device that sends midiclock data should work.
My sketch analyzes the duration of the first measure and then it starts to sync the jamman to every measure (or a multiple of...) on the midi stream.
User Ashimoke offers a solution for mounting the arduino inside the jamman.
do everything at you risk, a wrong connection can damage your devices.
Thanks to all who've made this work. I've always wanted to start tinkering with Arduinos - you just gave me an excuse to go out and buy one. My aims are pretty modest: just act as a battery-powered JamSync master so I can add a dedicated footswitch or two without having to go out and buy a Solo XT. Being battery-powered is helpful for outdoor use, and if I can't power an Arduino Nano (or similar) with a 9V battery, then I need to go back and retake my college electronics classes. I don't need a MIDI clock source if I'm only sending out JamSync traffic, so one of the smaller, shield-less models will hopefully suffice.
I just picked up a Vocal XT, which is now selling for $35. 3 of these plus an arduino and a fs3x (or just the fs3x parts) makes for a pretty badass little 3-track looper for under $150. The Express XTs can be had for under $60 now too. Hoping that people don't catch on until I've bought one or two more
John
I just picked up a Vocal XT, which is now selling for $35. 3 of these plus an arduino and a fs3x (or just the fs3x parts) makes for a pretty badass little 3-track looper for under $150. The Express XTs can be had for under $60 now too. Hoping that people don't catch on until I've bought one or two more
John
Good idea,jorymil wrote:@calde: Enrico, have you thought about putting your code out on GitHub/GitLab/etc.?
John
I've uploaded the code to https://github.com/Calde-github/Looperino.
Please note that:
1st time on Github
1st time on Arduino
Regards,
Enrico
Hello to all!
Now, this is a cool thread, thanks a lot to all the work that has been done on this topic so far! It is exactly what I was looking for. I am trying to get this sync setup working. So far I do get the sync signal (Jamman XT express LED 1 and 3 blinking a couple of times), after pressing record the red LED is blinking in wait mode but it never goes past this state. Any idea what I could have done wrong? I am not exactly sure how to connect the output of the arduino to the jamman though, do I need the 220 resistors (as per the MIDI specs) OR a voltage divider? DO I need to connect ground? Any help is greatly appreciated!
Now, this is a cool thread, thanks a lot to all the work that has been done on this topic so far! It is exactly what I was looking for. I am trying to get this sync setup working. So far I do get the sync signal (Jamman XT express LED 1 and 3 blinking a couple of times), after pressing record the red LED is blinking in wait mode but it never goes past this state. Any idea what I could have done wrong? I am not exactly sure how to connect the output of the arduino to the jamman though, do I need the 220 resistors (as per the MIDI specs) OR a voltage divider? DO I need to connect ground? Any help is greatly appreciated!
Hi Teebee,
if jamsync blink to sync signal, I think that Arduino-Jamsync side is Ok.
Jamsync wait for a start command... what do you connect to arduino as "Master clock"?
I made the interface at olimex https://www.olimex.com/Products/Duino/S ... DI-sch.pdf without the the components attached to A0-A5 and D6-D7
if jamsync blink to sync signal, I think that Arduino-Jamsync side is Ok.
Jamsync wait for a start command... what do you connect to arduino as "Master clock"?
I made the interface at olimex https://www.olimex.com/Products/Duino/S ... DI-sch.pdf without the the components attached to A0-A5 and D6-D7
@calde: Thanks a lot for your reply, I came to the same conclusion. I should have a closer look at the MIDI-in section, as I get a sync signal even without MIDI-in connected. So far I tried 2 different schematics (olimex and another one I found), which I hooked up to a Yamaha DX-200 that is definitely sending a MIDI-clock. Will the RX LED on the arduino itself blink upon receiving a MIDI-in signal? Knowing this would be really helpful for further troubleshooting.
@Teebee, the link between arduino and digitech is up with or without midi device connected.
Midi is received silently, no led flashes for debug.
For debug you could put led ON after
incoming_data = Serial.read();
and put OFF into
void sendLink() {
try...
Midi is received silently, no led flashes for debug.
For debug you could put led ON after
incoming_data = Serial.read();
and put OFF into
void sendLink() {
try...
Hello gentlemen,
Looks that you made a fantastic work and that is exactly what I need.
I am first time here. Please advise, I need to synchronize the JamMan Solo XT to the BeatBuddy (the BB - master; JM - slave).
Is it possible to use your code on Attiny85 with a schematics similar to https://ambinaut.files.wordpress.com/20 ... =768&h=320
Of course the output would be modified for the JM sync IN.
I am confident enough with electronics, but have no experience with programming.
Thanks for any help.
Looks that you made a fantastic work and that is exactly what I need.
I am first time here. Please advise, I need to synchronize the JamMan Solo XT to the BeatBuddy (the BB - master; JM - slave).
Is it possible to use your code on Attiny85 with a schematics similar to https://ambinaut.files.wordpress.com/20 ... =768&h=320
Of course the output would be modified for the JM sync IN.
I am confident enough with electronics, but have no experience with programming.
Thanks for any help.
@Nikogo: I don't think this will work, the proposed circuit is for the footswitch tap tempo and no midi signal as far as I understand.
@calde: Thanks for the code proposal, have to get back into this right now, as I have been travelling recently.
@calde: Thanks for the code proposal, have to get back into this right now, as I have been travelling recently.