The DL-4 was my go-to looper for many many years. When the M9 came out, I thought it could be the perfect replacement for my trusty DL-4, with nice improvements in the looper (longer time, undo, etc…) and having some high quality effects never hurt anyone either. Unfortunately, because of how the M9 is designed, in order to access the looper, you need to hold a button down to enter the looper. This really kills the “feel” of the pedal for me, as what I really loved about the DL-4 is that I could just step and loop right away, no thinking, no holding……just doing. Thankfully the M9 can take MIDI messages to control the looper.

After finishing The Party Bus sampler/mixer/looper, I began to realize the wonderful power/potential in microcontrollers. I had recently purchased an Arduino and was going through tutorials in order to learn how to program/use it. I though that an Arduino-based M9 MIDI Looper Controller would be a great project as it would let me do what I wanted with the M9, and having a nice guide/walkthrough could help others do the same thing.

The basic idea is to have a very small footprint set of buttons that will function just like a DL-4 looper, that you can access at any time, without having to touch the M9 at all. The only difference in functionality (that is planned at the moment anyways) is for the 4th button sending an UNDO message if you hold it down.

At the moment, this is a work in progress, so all pictures/code are just that. Works in progress. The hardware side of things is pretty much done, unless I feel like adding more LEDs, or completely revamping the idea. With 4 switches, and 4 LEDs, I should be able to program as much control as I need for a very long time (tap, doubletap, hold, twobuttonpress, etc…).

My code is pretty barebones at the moment, with controls over RECORD, OVERDUB, PLAY, STOP and PLAYONCE only working at the time of this pages creation. But the code for the 4th button, which will handle HALFSPEED, REVERSE, and UNDO is nearly done.

Once I have more completed, I will post better pictures, as well as some how-to information covering the hardware and software sides of the project.

For those that are less DIY inclined Disaster Area Amps has made a commercially available version of this (in 2 and 6 button configurations). Check it out.

Below are some pictures of the build and the current code.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

/*

* M9 MIDI LOOPER CONTROL v1.1 by Rodrigo Constanzo

* 4-Way Button Code by Jeff Saltzman

* 10-04-2010

*

* EXPLANATION

* -----------

* Four momentary footswitches are used to allow access to the Line 6 M9 looper remotely via MIDI.

* Buttons 1-3 function exactly as the first three buttons on the DL4 looper. Button 4 has three

* functions it controls. Single tap to go into half-speed mode. Double tap to go into reverse mode

* and press/hold to activate the UNDO/REDO function.

*

*/

/* TO DO

* add LED control

* button3 turns off LED2

* playonce button held down = retrigger/stutter?

* OR keep track of loop duration, and use it for LED3 (remember halfspeed!)

*/

#include// MIDI library

// ======= SWITCHES

Buttonbutton1=Button(8,PULLDOWN);// record/overdub

Buttonbutton2=Button(9,PULLDOWN);// play/stop

Buttonbutton3=Button(10,PULLDOWN);// play once

#define buttonPin11// halfspeed/reverse/undo button

// ======= LEDS

#define LED13// onboard LED for button press status

#define LED13// record/overdub status

#define LED24// play/stop status

#define LED35// play once status

#define ledPin15// half-speed loop status

#define ledPin26// reverse status

#define ledPin315// unused

#define ledPin414// unused

// ======= LED variables

booleanledVal1=false;// state of halfspeed LED

booleanledVal2=false;// state of reverse LED

booleanledVal3=false;// unused

booleanledVal4=false;// unused

// ======= STATE variables

intstate=0;// state of stop(0),play(1),record(2),overdub(3)

// ======= TIMING variables

intdebounce=5;// ms debounce for halfspeed/reverse

intDCgap=250;// max ms between clicks for a double click event

intholdTime=700;// ms hold period: how long to wait for press+hold event

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

voidsetup(){

pinMode(buttonPin,INPUT);// halfspeed/reverse/undo

digitalWrite(buttonPin,HIGH);

pinMode(LED,OUTPUT);// button press LED status

pinMode(LED1,OUTPUT);// record/overdub LED

pinMode(LED2,OUTPUT);// play/stop LED

pinMode(LED3,OUTPUT);// play once LED

pinMode(ledPin1,OUTPUT);// halfspeed

pinMode(ledPin2,OUTPUT);// reverse

pinMode(ledPin3,OUTPUT);// unused

pinMode(ledPin4,OUTPUT);// unused

digitalWrite(LED1,LOW);

digitalWrite(LED2,LOW);

digitalWrite(LED3,LOW);

digitalWrite(ledPin1,LOW);// digitalWrite(ledPin1, ledVal1);

digitalWrite(ledPin2,LOW);// digitalWrite(ledPin2, ledVal2);

digitalWrite(ledPin3,LOW);// digitalWrite(ledPin3, ledVal3);

digitalWrite(ledPin4,LOW);// digitalWrite(ledPin4, ledVal4);

// ======= MIDI

Serial.begin(31250);

}

voidloop(){

// ======= BUTTON1

if(button1.uniquePress()){

// ======= RECORD NEW LOOP ////

if(state==0){

state=2;

Record();

}

// ======= OVERDUB (FROM RECORD STATE) ////

elseif(state==2){

state=3;

Overdub();

}

// ======= OVERDUB (TO PLAY STATE)

elseif(state==3){

state=1;

Overdub();

}

// ======= RECORD (TO PLAY STATE)

elseif(state==2){

state=1;

Play();

}

// ======= OVERDUB (FROM PLAY STATE)

elseif(state==1){

state=3;

Overdub();

}

}

// ======= BUTTON2

if(button2.uniquePress()){

// ======= PLAY

if(state==0){

state=1;

Play();

}

// ======= STOP

elseif(state==1){

state=0;

Stop();

}

}

// ======= BUTTON3

if(button3.uniquePress()){

state=0;

PlayOnce();

}

// ======= BUTTON4

intb=checkButton();// halfspeed/reverse/undo button press

// ======= HALFSPEED/REVERSE/UNDO

if(b==1)clickEvent();

if(b==2)doubleClickEvent();

if(b==3)holdEvent();

}

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

// Events to trigger by click, double-click, and press+hold

voidclickEvent(){

ledVal1=!ledVal1;

digitalWrite(ledPin1,ledVal1);

HalfSpeed();

}

voiddoubleClickEvent(){

ledVal2=!ledVal2;

digitalWrite(ledPin2,ledVal2);

Reverse();

}

voidholdEvent(){

ledVal3=!ledVal3;

digitalWrite(ledPin3,ledVal3);

Undo();

}

//void longHoldEvent() {

//ledVal4 = !ledVal4;

//digitalWrite(ledPin4, ledVal4);

//}

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

//============== GUTS BEYOND HERE =================

//============== DO NOT MESS WITH =================

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

// ======= MIDI Messages To Send

voidRecord(){

Serial.print(0xb0,BYTE);

Serial.print(50,BYTE);

Serial.print(127,BYTE);

digitalWrite(LED,HIGH);

digitalWrite(LED,LOW);

}

voidOverdub(){

Serial.print(0xb0,BYTE);

Serial.print(50,BYTE);

Serial.print(0,BYTE);

digitalWrite(LED,HIGH);

digitalWrite(LED,LOW);

}

voidPlay(){

Serial.print(0xb0,BYTE);

Serial.print(28,BYTE);

Serial.print(127,BYTE);

digitalWrite(LED,HIGH);

digitalWrite(LED,LOW);

}

voidStop(){

Serial.print(0xb0,BYTE);

Serial.print(28,BYTE);

Serial.print(0,BYTE);

digitalWrite(LED,HIGH);

digitalWrite(LED,LOW);

}

voidPlayOnce(){

Serial.print(0xb0,BYTE);

Serial.print(80,BYTE);

Serial.print(127,BYTE);

digitalWrite(LED,HIGH);

digitalWrite(LED,LOW);

}

voidHalfSpeed(){

Serial.print(0xb0,BYTE);

Serial.print(36,BYTE);

Serial.print(127,BYTE);

digitalWrite(LED,HIGH);

digitalWrite(LED,LOW);

}

voidReverse(){

Serial.print(0xb0,BYTE);

Serial.print(85,BYTE);

Serial.print(127,BYTE);

digitalWrite(LED,HIGH);

digitalWrite(LED,LOW);

}

voidUndo(){

Serial.print(0xb0,BYTE);

Serial.print(82,BYTE);

Serial.print(127,BYTE);

digitalWrite(LED,HIGH);

digitalWrite(LED,LOW);

}

// ======= Timing guts for 4-way button

// Button timing variables

intlongHoldTime=5000;// ms long hold period: how long to wait for press+hold event (not used)

// Other button variables

booleanbuttonVal=HIGH;// value read from button

booleanbuttonLast=HIGH;// buffered value of the button's previous state

6 Comments

Rich from Line 6 here. I love how you made this all work together. Very cool. Love Pedaltrain as well.

I just wanted to say one thing for guys who love the DL4 Looper and by the M9 just for Looper. You CAN actually use it just like the DL4 by putting on one Delay you like and then putting it into looper mode and leaving it. That makes it just like the DL4 for the entire time it is on. You can kill the delay just like on the DL4 because you will have control over the one delay only that you get with DL4.

So to clarify, if you want instant control over the looper AND control over many FX at the same time, this is a great way to go.

This is exactly what I’m looking to buy. If Line6 offered a switch like this, I’d pay good money to have the M9 Looper functions right at my feet. Unfortunately, I am not the DIY kind and wouldn’t be able to build something like this. Great work, mate!

Hmm, it could be because of a change in the Arduino libraries. The original code for this is quite old, possibly before even the Arduino 1.0 standard. Wouldn’t really know where to start in updating this though, as my level of Arduino syntax/library changes isn’t too great.