Digitech JamSync - How does it work?

All about modern commercial stompbox circuits from Electro Harmonix over MXR, Boss and Ibanez into the nineties.
User avatar
calde
Information
Posts: 13
Joined: 09 Sep 2016, 23:11
Has thanked: 2 times
Been thanked: 10 times

Post by calde »

@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 ...

User avatar
calde
Information
Posts: 13
Joined: 09 Sep 2016, 23:11
Has thanked: 2 times
Been thanked: 10 times

Post by calde »

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.

User avatar
teebee
Information
Posts: 4
Joined: 27 Apr 2017, 21:30
Has thanked: 2 times

Post by teebee »

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?

User avatar
Nikogo
Information
Posts: 6
Joined: 30 May 2017, 01:52
Has thanked: 2 times
Been thanked: 4 times

Post by Nikogo »

@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.

User avatar
calde
Information
Posts: 13
Joined: 09 Sep 2016, 23:11
Has thanked: 2 times
Been thanked: 10 times

Post by calde »

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!

User avatar
Nikogo
Information
Posts: 6
Joined: 30 May 2017, 01:52
Has thanked: 2 times
Been thanked: 4 times

Post by Nikogo »

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

User avatar
Guitar Rabbit
Information
Posts: 1
Joined: 29 Aug 2017, 14:29
Has thanked: 3 times
Been thanked: 2 times

Post by Guitar Rabbit »

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

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.

User avatar
manunit
Information
Posts: 1
Joined: 29 Dec 2017, 14:10
Has thanked: 1 time

Post by manunit »

Thanks,

Will be trying this as a new years project.

User avatar
jorymil
Information
Posts: 3
Joined: 16 Feb 2017, 06:49
Has thanked: 3 times

Post by jorymil »

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:



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.

User avatar
baob
Information
Posts: 1
Joined: 26 May 2018, 10:15
Has thanked: 2 times

Post by baob »

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:



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.

User avatar
Haus
Information
Posts: 1
Joined: 10 Jun 2018, 22:06
Been thanked: 1 time

Post by Haus »

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?

User avatar
joeSeggiola
Information
Posts: 3
Joined: 07 Jul 2018, 11:36
Has thanked: 3 times
Been thanked: 5 times

Post by joeSeggiola »

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);

}


User avatar
grayzone
Information
Posts: 2
Joined: 02 Sep 2018, 13:24
Has thanked: 1 time
Been thanked: 2 times

Post by grayzone »

Many thank for all your work on this

Ive got a great signal coming into a an Elegoo UNO R3 from Pams New Workout modular - extending this principle to hook up a guitar with a live Eurorack modular rig

code Im using is below -thanks to JoeSeggiola!

No joy with the Transmit to serial midi - checked tip, ring and ground and they are live tip about 4.7 volts, ring 3.3 ish ground fine - no recognition from the JamMan.

Im brand new at this, but so close - i was overjoyed when the modular clock appeared on the flashing LED's - input must be fine and tempo changes are picked up by the Uno and shown as changes in the LED rates - all good

But no JamMan joy :(

something fundamental wrong with code? - any help appreciated

Code: Select all

// CONFIGURATION =============================================================

const HardwareSerial *JM = 1; // 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 = 12; // Measure LED (quarter 1)
const int LED_BEAT_Q = 11; // 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);

}


User avatar
mikebike
Information
Posts: 13
Joined: 09 Jan 2009, 19:48

Post by mikebike »

Hello all!

I attempting to build the midi to jam sync, but my arduino loader wont let me upload the program.

The loader is showing an error message: function does not declare paramaters

The program is refering to the first line of code after //sysex arrays

I am new to arduino, so its possible I am missing something simple here.

thanks!

User avatar
mikebike
Information
Posts: 13
Joined: 09 Jan 2009, 19:48

Post by mikebike »

NVM just needed to update the IDE!

User avatar
joeSeggiola
Information
Posts: 3
Joined: 07 Jul 2018, 11:36
Has thanked: 3 times
Been thanked: 5 times

Post by joeSeggiola »

grayzone wrote:No joy with the Transmit to serial midi
Hi grayzone. If you see the LEDs blinking correctly to tempo, then probably the problem is just for serial transmission, as you said. Check these:
  • 1) Are you using Arduino pin 1 TX for transmitting?

    2) Do you see a dot appearing on the bottom right of the JamMan display a couple of second after turning on the Arduino? This should happens also when no clock signal is sent, and it confirm that the JamMan receives the MIDI-like messages that puts it into tempo slave mode.

    3) What Arduino board are you using? I see from your code that you replaced &Serial1 with a 1, why? In fact, this is an error, because I was using the secondary serial port on an Arduino Mega when testing my code. To use the Arduino default serial port (pin 1 TX), which is present in every board model, you should use just &Serial. In doubt, you can replace every code occurrence of JM-> to the standard syntax Serial., if you are curious of what I'm talking about, try to read a guide on C++ pointers.
Please let me know!

User avatar
grayzone
Information
Posts: 2
Joined: 02 Sep 2018, 13:24
Has thanked: 1 time
Been thanked: 2 times

Post by grayzone »

Many thanks - it works!!!!!!

in answer to your questions and for the completeness of others trying to solve this

1) Are you using Arduino pin 1 TX for transmitting?

** yes i was

2) Do you see a dot appearing on the bottom right of the JamMan display a couple of second after turning on the Arduino? This should happens also when no clock signal is sent, and it confirm that the JamMan receives the MIDI-like messages that puts it into tempo slave mode.

** no i did not - that made me think since i had the input working that it had to be a serial output issue

3) What Arduino board are you using? I see from your code that you replaced &Serial1 with a 1, why? In fact, this is an error, because I was using the secondary serial port on an Arduino Mega when testing my code. To use the Arduino default serial port (pin 1 TX), which is present in every board model, you should use just &Serial. In doubt, you can replace every code occurrence of JM-> to the standard syntax Serial., if you are curious of what I'm talking about, try to read a guide on C++ pointers.

** you were right here too - am using the elegy uno r3 - so yes it was simple change to &serial

** so i changed that uploaded and the sync light comes on

** a couple of minutes later - guitar is in perfect sync with the modular

good work!!!!!

Many thanks

User avatar
goyya76
Information
Posts: 2
Joined: 31 Oct 2018, 23:17

Post by goyya76 »

Dear all, I have been reading this thread with a lot of interest, as I started messing around with a jamman solo xt that i bought because it looked like the only looper with the possibility to tap tempo and timestretch a loop WHILE the loop is playing....anyway I didn't understand that the loop has to be stored in order to do that! unfortunately storing isn't possible hands free - maybe some of you can tell if sending a sync signal through jamsync can modify the tempo of a loop that has not been stored before? I would like to record a loop on the fly and use it later on in the song to solo onto it, but would also like to correct the timing if as a band we drift away a bit with the tempo...
Another option would be something put above the store button to be pressed with the foot, or maybe modding the pedal with an arduino connected to the foot button and the store button (receives the press of the foot button and grounds twice the store button, but I guess some kind of relay would be required)...

Thanks in advance, Francesco

User avatar
Electribe_Jamman
Information
Posts: 1
Joined: 24 Sep 2018, 18:40

Post by Electribe_Jamman »

Hi all,
first of all thank you very much for putting so much effort into this project! This is exactly what I am looking for.
I am currently facing the same issue as teebee some time ago: Jamman says that he is in sync but I cannot start a loop. The red light only blinks and Jamman waits for a start signal.
This likely indicates that reading the incoming midi signal does not work properly yet!?

It's my first 'real' arduino project and I am not very familiar with electronics in general but I tried to build the Midi shield following the Olimex schematics (without the analogue pins and the LEDs).
Since my midi signal comes in (from an electribe 2 sampler) via a stereo jack, I connected the tip to midi pin 4 and the ring to midi pin 5. Sleeve (pin 2) stays unconnected.

Any suggestion what a beginner might get wrong?

User avatar
adramelek
Information
Posts: 1
Joined: 18 Nov 2018, 18:44

Post by adramelek »

Hello !

I'm trying to find how to make a master clock for my Jamman Express XT. Do you know if the jamman Express sysex deals with metrics (4/4 etc...). For me the JM Express is the simplest version of Digitech loopers, I just want to send a sync signal with only the loop lenght and no more, I don't want to deal with first bars and quarter or tempo. I need just a sync sysex that sends the lenght of a pulse. Do you think that's possible ? Regards,
Cédric

Post Reply