Digitech JamSync - How does it work?

All about modern commercial stompbox circuits from Electro Harmonix over MXR, Boss and Ibanez into the nineties.

Re: Digitech JamSync - How does it work?

Postby calde » 06 Jun 2017, 11:25

@Nikogo, the arduino sketch needs only the serial out and serial in.

But:

attiny85 clock is internal and I have some doubt about the stability to sync to midi signal

attiny85 has very low memory

attiny85 (I think) supports the serial communication by external library, that eats some memory

However someone could try to compile and see the size ...

For this message the author calde has received thanks:
Nikogo (24 Jun 2017, 16:54)
calde
 
Posts: 13
Joined: 10 Sep 2016, 00:11
Has thanked: 2 times
Have thanks: 7 times

Re: Digitech JamSync - How does it work?

Postby calde » 06 Jun 2017, 21:51

Hi,

I've tried to compile the sketch for AtTiny85, but I've got this:

Sketch uses 5414 bytes (264%) of program storage space. Maximum is 2048 bytes.
Global variables use 266 bytes (207%) of dynamic memory, leaving -138 bytes for local variables. Maximum is 128 bytes.
Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it.
Error compiling for board ATtiny25/45/85.


I have added the board:
https://raw.githubusercontent.com/damel ... index.json

And I have added at top:
Code: Select all
#include <SoftwareSerial.h>
const int rx=3;
const int tx=4;
SoftwareSerial Serial(rx, tx);


I think that Attiny85 isn't suitable for this scope.
calde
 
Posts: 13
Joined: 10 Sep 2016, 00:11
Has thanked: 2 times
Have thanks: 7 times

Re: Digitech JamSync - How does it work?

Postby teebee » 07 Jun 2017, 15:34

Finally it works, this is super cool, it opens up a whole bunch of new possibilities! I don't know exactly what was wrong in my first attempts, I guess there were a couple of concurrent things causing trouble: MIDI clock was unintentionally switched to MIDI thru on my source device, MIDI out plug was loose, and the MIDI in connectors on my arduino were swapped (well, I swapped them at one point). @calde: thanks so much for your help!

Now, to push this project a little further: I could imagine to use the jamman as a master device in some situations. How would that work?
teebee
 
Posts: 4
Joined: 27 Apr 2017, 22:30
Has thanked: 2 times
Have thanks: 0 time

Re: Digitech JamSync - How does it work?

Postby Nikogo » 24 Jun 2017, 16:49

@Teebee: The proposed Attiny85 schematics could be modified to have the MIDI style output. My initial doubts were about the internal clock stability and the program compatibility.
@Calde: Enrico, muchas gracias for your research, the code, and your advice.
I have ordered a few Arduino Nano and am impatiently waiting for a slow boat from China.
Meanwhile in a search for a compact design I found that the Nano can be placed inside the BeatBuddy under the display PCB. I would need 6 wires to connect it.
Two wires for 9V DC could be taken from the DC power connector or from the PCB (it has nice big soldering pads);
Two wires from MIDI Out could be taken from the PCB near the MIDI connector to be an input for Nano;
Two wires for the output from Nano could be connected to the two empty contacts of MIDI PS/2 connector. So the MIDI Input and Output of BeatBuddy would be still available but for connection to a JamMan I would need a special cable. I made such a cable from the old mouse PS/2 connector and the headphone cable with 3.5mm stereo plug.
I will keep the MIDI shield circuits. But I guess the optical isolator may not be even needed. Because the ground is common and the 5V DC power is the same for BB and Nano it would be enough to connect the MIDI Out from BB with a single wire to Nano's RxD and the TxD through 220 Ohm resistor to JamMan (using the 5VDC through 220 Ohm from the MIDI Out). The only doubt is if the BB MIDI out would be overloaded when the real MIDI connection is used (the Nano would be still connected inside).
Please give your opinion.

For this message the author Nikogo has received thanks:
Guitar Rabbit (29 Aug 2017, 15:33)
Nikogo
 
Posts: 6
Joined: 30 May 2017, 02:52
Has thanked: 2 times
Have thanks: 3 times

Re: Digitech JamSync - How does it work?

Postby calde » 24 Jun 2017, 23:55

Hi Nikogo,

I am not so expert in electronics to help you with optical isolator.

About the Midi out, I think that is safer disconnect the midi out connector of the BeatBuddy and change it in MIDI THRU. You can find schematics online.

good work!

For this message the author calde has received thanks:
Guitar Rabbit (29 Aug 2017, 15:32)
calde
 
Posts: 13
Joined: 10 Sep 2016, 00:11
Has thanked: 2 times
Have thanks: 7 times

Re: Digitech JamSync - How does it work?

Postby Nikogo » 19 Aug 2017, 15:16

An update for installation of Arduino Nano in BeatBuddy for synchronising with JamMan Solo XT.
The Nano is connected inside BB with 4 wires (30 AWG) and need only 2 headers (2 pins each) soldered into last holes of each row on Nano board (GND, VIN and Rx0, Tx1). The shield boars is a piece of a breadboard 18x8 mm with 2 female headers and a single 220 Ohm resistor. The GND is connected to the ground tab (-9VDC) and VIN - to +9VDC tab where the BB power connector is connected to its board.
The Rx0 Nano input is connected to the MIDI output pin on MIDI connector. If looking on left external side of BB it is the right pin in top row. The MIDI connector's bottom left pin is MIDI ground, bottom right - not connected, the middle row pins are MIDI input, the top left is +5V thru 220 Ohm resistor of MIDI output.
The Tx1 Nano output thru the 220 Ohm resistor (on shield board) should be connected to the MIDI connector's bottom right pin.
I made the synchro BB-JM cable from a headphone cable with 3.5 mm stereo jack plug and the old PC mouse connector. It connects the BB MIDI top left (+5V) pin to the ring and the bottom right BB MIDI pin (Tx1) to the tip of 3.5 plug.
Such connection allows to use the BB MIDI connector for MIDI purposes without restrictions. The BB MIDI output that I connected to Rx0 has a buffer on OpAmp follower and can easily drive two parallel ports, so the Rx0 Nano input does not affect its functionality. Between the OpAmp and the MIDI pin there is a 220 Ohm resistor. The Nano input could be taken before or after that resistor.
I wrapped Nano with Kapton tape for insulation.
And it works.
Thank you all

For this message the author Nikogo has received thanks: 2
Guitar Rabbit (29 Aug 2017, 15:32), Nocentelli (19 Aug 2017, 22:29)
Nikogo
 
Posts: 6
Joined: 30 May 2017, 02:52
Has thanked: 2 times
Have thanks: 3 times

Re: Digitech JamSync - How does it work?

Postby Guitar Rabbit » 29 Aug 2017, 15:42

Hi all, I just wanted to say thanks for this great project!
It makes the Jam Man so much easier to use for looping when connected to a drum machine, in my case the iOS app "Patterning".
This was my first Arduino project and it worked with a cheap clone and a midi breakout board with the Jam Man Solo XT.

Here is a shopping list for anyone interested:

XCSOURCE® UNO R3 Rev3 Board Development Board ATmega328P CH340G AVR Arduino Compatible Board +Cable for Arduino DIY TE113 £5.99
from https://www.amazon.co.uk/dp/B00SR4FLMI/ ... 11_TE_item

5 Pin DIN Plug 5DIN-PLUG £0.44 1 £0.44
MIDI Breakout Board MIDI-BB £6.00 1 £6.00
3.5mm Stereo Jack Plug STEREOJACK £0.40 1 £0.40
from http://www.hobbytronics.co.uk/

At first I was unsure about aforementioned voltage dividers which seem to be unnecessary, it works fine without.

For this message the author Guitar Rabbit has received thanks:
manunit (29 Dec 2017, 15:27)
Guitar Rabbit
 
Posts: 1
Joined: 29 Aug 2017, 15:29
Has thanked: 3 times
Have thanks: 1 time

Re: Digitech JamSync - How does it work?

Postby manunit » 29 Dec 2017, 15:26

Thanks,

Will be trying this as a new years project.
manunit
 
Posts: 1
Joined: 29 Dec 2017, 15:10
Has thanked: 1 time
Have thanks: 0 time

Re: Digitech JamSync - How does it work?

Postby jorymil » 06 Jan 2018, 12:46

Has anyone gotten their hands on a SDRUM pedal to see what the JamSync output looks like? Based on this thread:

https://www.thegearpage.net/board/index ... l.1846095/

it sounds like it's sending out actual MIDI start/stop/clock messages--either that, or that other devices can handle "close enough" to be able to sync with it. Here's a YouTube video of someone who's synced up a SDRUM with a Ditto X4 looper:

https://www.youtube.com/watch?v=9hsWMux0_3Q

Would like to see what's actually coming over the wires, but am finding it hard to justify $150-200 for something I'm not really interested in using regularly. (I play the drums _myself_, darnit.) Might end up buying a used one, analyzing the data, then re-selling it.
jorymil
 
Posts: 3
Joined: 16 Feb 2017, 07:49
Has thanked: 3 times
Have thanks: 0 time

Re: Digitech JamSync - How does it work?

Postby baob » 26 May 2018, 13:31

jorymil wrote:Has anyone gotten their hands on a SDRUM pedal to see what the JamSync output looks like? Based on this thread:

https://www.thegearpage.net/board/index ... l.1846095/

it sounds like it's sending out actual MIDI start/stop/clock messages--either that, or that other devices can handle "close enough" to be able to sync with it. Here's a YouTube video of someone who's synced up a SDRUM with a Ditto X4 looper:

https://www.youtube.com/watch?v=9hsWMux0_3Q

Would like to see what's actually coming over the wires, but am finding it hard to justify $150-200 for something I'm not really interested in using regularly. (I play the drums _myself_, darnit.) Might end up buying a used one, analyzing the data, then re-selling it.


I'm also interested in knowing more about jamsync on SDRUM. The existence of this thread and the syncman product give me confidence (not 100%, but a lot) that a hybrid Jamsync/MIDI system could be made to work in the way I visualise.

I'm looking for a system that's based around an SDrum as master (it won't slave), and there's a problem there ... SDrum, while it uniquely sends standard (non-sysex) midi, does not transmit 'midi continue' and also, even through jamsync, does not support some jamsync functionality (according to the manual) like 'sequential record'. I suspect 'sequential record' is dependent on the jamsync equivalent of 'midi continue'.

SUMMARY: yes, I'd like to know more about what the SDrum does over midi and jamsync.
baob
 
Posts: 1
Joined: 26 May 2018, 11:15
Has thanked: 2 times
Have thanks: 0 time

Re: Digitech JamSync - How does it work?

Postby Haus » 10 Jun 2018, 23:14

Hi all! If I want to trigger this thing from a sync signal, instead of from midi, how would the design change? The sync is a 5V square pulse each 8th note (generated by a Volca Sample). The clock has to be calculated from the incoming signal, and no midi shield is necessary, right?
Haus
 
Posts: 1
Joined: 10 Jun 2018, 23:06
Has thanked: 0 time
Have thanks: 0 time

Re: Digitech JamSync - How does it work?

Postby joeSeggiola » 07 Jul 2018, 12:58

Thank you all for your work here! I used calde GitHub code as a starting point to make a version that takes a clock/pulse input instead of MIDI input, for using it with modular synths and general analog gear. I want to share it go give something back :)

Haus wrote:Hi all! If I want to trigger this thing from a sync signal, instead of from midi, how would the design change? The sync is a 5V square pulse each 8th note (generated by a Volca Sample). The clock has to be calculated from the incoming signal, and no midi shield is necessary, right?


Hi Haus, that's exactly what I needed and what I ended up doing. The following is my code. I'm testing it with a Korg SQ-1 clock output, and it works perfectly. To detect clock pulses with the highest reliability possible, I'm using Arduino's interrupts. The input signal is taken from the Korg SQ-1 clock output using a mono 3.5" jack (but you can use a stereo cable too), with the tip connected directly into interrupt pin and ground to GND. The output is the serial MIDI on a stereo jack into the JM sync input, as already discussed in the thread:

    - TX out (pin 1) -> 220ohm -> jack tip
    - 3.3V -> 220ohm -> jack ring
    - GND -> jack ground

In the beginning of the file you can customize these configurations. For example in my case every pulse is a 4th, if it'd be 8th you have to set PPQ = 2 instead (pulse per quarter). I also added some LEDs to blink on quarters and measures.

Code: Select all
// CONFIGURATION =============================================================

const HardwareSerial *JM = &Serial1; // Serial port for JM sync cable (MIDI-like)
const HardwareSerial *DEBUG = 0; // &Serial to debug on USB, or zero to disable debugging

const byte PULSE_INTERRUPT_PIN = 2; // Digital pin for pulse clock input

const int LED_PLAYING_PIN = 13; // Playing/stop LED
const int LED_BEAT_M = 39; // Measure LED (quarter 1)
const int LED_BEAT_Q = 35; // Quarter LED (quarter 2, 3, 4)
const int LEDS_DURATION_MS = 80; // LED flashing duration

const unsigned int PPQ = 1; // Incoming pulses per quarter
const unsigned int QPM = 4; // Quarters per measure

const unsigned int STOP_Q = 3; // How many expected quarters missing to detect clock stopped

// ===========================================================================

const int JM_LINK_PERIOD_MS = 400;

// JM sync signal packets, from:
// http://fuzzysynth.blogspot.com/2015/06/digitech-jam-man.html
// https://github.com/Calde-github/Looperino/blob/master/Looper.ino
const byte JM_SYNC[] {0xF0, 0x00, 0x00, 0x10, 0x7F, 0x62, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7};
const byte JM_LINK[] {0xF0, 0x00, 0x00, 0x10, 0x7F, 0x62, 0x01, 0x00, 0x01, 0x01, 0xF7};

bool playing = false;

unsigned int pulseCounter = 0;
unsigned int quarterCounter = 0;
unsigned long quarterLastMicros = 0;
unsigned long measureDurationMicros = 0;
unsigned long measureLastMicros = 0;
unsigned int bpm = 0; // Computed BPM

volatile bool pulseFlag = false; // A pulse has been detected in the ISR

unsigned long linkLastMillis = 0;

void setup() {

   // Debugging
   if (DEBUG) DEBUG->begin(9600);

   // Status LEDs setup
   pinMode(LED_PLAYING_PIN, OUTPUT);
   pinMode(LED_BEAT_M, OUTPUT);
   pinMode(LED_BEAT_Q, OUTPUT);
   digitalWrite(LED_PLAYING_PIN, LOW);
   digitalWrite(LED_BEAT_M, LOW);
   digitalWrite(LED_BEAT_Q, LOW);

   // JM MIDI-like out
   JM->begin(31250);

   // Send JM link
   linkMaintain();

   // Attach pulses interrupt
   pinMode(PULSE_INTERRUPT_PIN, INPUT_PULLUP);
   attachInterrupt(digitalPinToInterrupt(PULSE_INTERRUPT_PIN), pulseFlagSet, RISING);

}

void loop() {
   pulseFlagProcess();
   detectStop();
   leds();
   linkMaintain();
}

void pulseFlagSet() {
   pulseFlag = true;
}

void pulseFlagProcess() {
   
   if (pulseFlag) {
      pulseFlag = false;

      unsigned long nowMicros = micros();

      // If it was stopped, resume
      if (!playing) {

         if (DEBUG) DEBUG->println("Resuming...");

         // Fake last measure in order to keep last known tempo
         if (measureDurationMicros > 0) {
            measureLastMicros = nowMicros - measureDurationMicros;
         }

         pulseCounter = 0;
         quarterCounter = 0;
         quarterLastMicros = nowMicros;
         playing = true;
         if (DEBUG) DEBUG->println("Playing.");

      } else {

         // Count pulse
         pulseCounter = (pulseCounter + 1) % PPQ;

         // New quarter?
         if (pulseCounter == 0) {
            quarterCounter = (quarterCounter + 1) % QPM;
            quarterLastMicros = nowMicros;
            if (DEBUG) {
               DEBUG->print("Got quarter: ");
               DEBUG->println(quarterCounter);
            }
         }

      }

      // New measure?
      if (pulseCounter == 0 && quarterCounter == 0) {

         // Compute BPM
         if (measureLastMicros > 0) { // Got the first measure ever?
            if (DEBUG) DEBUG->println("Got measure.");
            measureDurationMicros = nowMicros - measureLastMicros;
            bpm = round(QPM * 60000000.0 / measureDurationMicros);
            if (DEBUG) {
               DEBUG->print("Sending sync with tempo: ");
               DEBUG->print(bpm);
               DEBUG->println(" BPM");
            }

            // Send JM sync signal with BPM and measure duration information
            syncSend();

         } else {
            if (DEBUG) DEBUG->println("Got first measure ever.");
         }

         measureLastMicros = nowMicros;

      }

   }
   
}

void detectStop() {
   
   // Detect if stopped (3 quarters missing)
   if (playing) {
      if (measureDurationMicros > 0) { // I know how much a measure is expected to be long
         unsigned long quarterExpectedDuration = measureDurationMicros / QPM;
         if (micros() - quarterLastMicros > STOP_Q * quarterExpectedDuration) {
            playing = false;
            if (DEBUG) DEBUG->println("Stop detected!");
         }
      }
   }
   
}

void leds() {
   
   // Playing indicator
   digitalWrite(LED_PLAYING_PIN, playing ? HIGH : LOW);
   
   // Beat indicators
   bool ledsOn = playing && (micros() - quarterLastMicros < LEDS_DURATION_MS * 1000);
   digitalWrite(LED_BEAT_M, ledsOn && quarterCounter == 0 ? HIGH : LOW);
   digitalWrite(LED_BEAT_Q, ledsOn && quarterCounter > 0 ? HIGH : LOW);
   
}

void linkMaintain() {
   
   // Keep JM link active by sending the link packet every ~400ms
   if (millis() - linkLastMillis > JM_LINK_PERIOD_MS) {
      JM->write(JM_LINK, sizeof(JM_LINK));
      linkLastMillis = millis();   
   }
   
}

void syncSend() {

   // From:
   // https://github.com/Calde-github/Looperino/blob/master/Looper.ino

   // Copy base JM sync packet
   int syncPacketSize = sizeof(JM_SYNC);
   byte syncPacket[syncPacketSize];
   for (int i = 0; i < syncPacketSize; i++) syncPacket[i] = JM_SYNC[i];

   // BPM
   syncPacket[7] = 66 + 8 * ((63 < bpm) && (bpm < 128) || bpm > 191) ;
   syncPacket[11] = (4 * bpm > 127 && 4 * bpm < 256) * (4 * bpm - 128) +
                    (2 * bpm > 127 && 2 * bpm < 256) * (2 * bpm - 128) +
                    (bpm > 127 && bpm < 256) * (bpm - 128);
   syncPacket[12] = 1 * (bpm > 127) + 66;

   // Measure length
   unsigned long loopTime = floor(measureDurationMicros / 1000.0);
   int x = floor(log(loopTime / 2000.0) / log(4.0));
   int b163 = (loopTime / (2000.0 * pow(4.0, x))) > 2;
   int y = 2 * pow(2, b163) * pow(4, x);
   int w = floor(loopTime / y);
   syncPacket[15] = 64 + 8 * b163;
   syncPacket[20] = 64 + x;
   syncPacket[19] = 128 * (0.001 * w - 1);
   syncPacket[18] = pow(128.0, 2) * (0.001 * w - 1 - syncPacket[19] / 128.0);
   syncPacket[17] = pow(128.0, 3) * (0.001 * w - 1 - syncPacket[19] / 128.0 - syncPacket[18] / pow(128.0, 2));

   // Command (SYNC)
   syncPacket[21] = 5;

   // Checksum XOR
   byte z = 0;
   for (int i = 7; i < 22; i++) z = z ^ syncPacket[i];
   syncPacket[22] = z;

   JM->write(syncPacket, syncPacketSize);

}


For this message the author joeSeggiola has received thanks:
marshmellow (07 Jul 2018, 13:16)
joeSeggiola
 
Posts: 1
Joined: 07 Jul 2018, 12:36
Has thanked: 0 time
Have thanks: 1 time

Previous

Return to Modern Stompbox Effects (1975 - ...)

Who is online

Users browsing this forum: arsenal32, Google [Bot], MilesXC, ppfai, Sparrows78 and 9 guests