Source

ArduinoProjects / Experimental / MusicMachine / MusicMachine.ino

Full commit
  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
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
// MusicMachine
// http://www.hacktronics.com/Tutorials/arduino-and-7-segment-led.html
// License: http://www.opensource.org/licenses/mit-license.php (Go crazy)
// Created by: Jody McAdams
// twitter: @MegaJiXiang

//Pins
int g_potPin = 0;
int g_buzzerPin = 11;
int g_buttonPin1 = 12;
int g_buttonPin2 = 13;
int g_ledPin_Green = 1;
int g_ledPin_Blue = 2;

/* 
RadioShack 7 Segment Display
Pins starts from top left

1. Anode F          LED Pin 1        Arduino Pin 8
2. Anode G          LED Pin 2        Arduino Pin 9
3. No Pin
4. Common Cathode                    Arduino Ground
5. No Pin
6. Anode E          LED Pin 6        Arduino Pin 7
7. Anode D          LED Pin 7        Arduino Pin 6
8. Anode C          LED Pin 8        Arduino Pin 5
9. Anode RHDP       LED Pin 9        Arduino Pin 10
10. No Pin
11. No Pin
12. Common Cathode                   Arduino Ground
13. Anode B         LED Pin 13       Arduino Pin 4
14. Anode A         LED Pin 14       Arduino Pin 3
*/

// Define the LED digit patterns for 0 - 9
// 1 = LED on, 0 = LED off, in this order:
// Arduino pin: 3,4,5,6,7,8,9,

const char g_numDigits = 10;
byte seven_seg_digits[g_numDigits][7] = {
{ 1,1,1,1,1,1,0 },  // = 0
{ 0,1,1,0,0,0,0 },  // = 1
{ 1,1,0,1,1,0,1 },  // = 2
{ 1,1,1,1,0,0,1 },  // = 3
{ 0,1,1,0,0,1,1 },  // = 4
{ 1,0,1,1,0,1,1 },  // = 5
{ 1,0,1,1,1,1,1 },  // = 6
{ 1,1,1,0,0,0,0 },  // = 7
{ 1,1,1,1,1,1,1 },  // = 8
{ 1,1,1,0,0,1,1 }   // = 9
};

// Define the LED digit patterns for the music notes
const char g_numNotes = 13;                                                          
byte seven_seg_notes[g_numNotes][8] = {                                 
{ 1,0,0,1,1,1,0,0 },  // = C
{ 1,0,0,1,1,1,0,1 },  // = C#
{ 0,1,1,1,1,0,1,0 },  // = D
{ 0,1,1,1,1,0,1,1 },  // = D#
{ 1,0,0,1,1,1,1,0 },  // = E
{ 1,0,0,0,1,1,1,0 },  // = F
{ 1,0,0,0,1,1,1,1 },  // = F#
{ 1,0,1,1,1,1,1,0 },  // = G
{ 1,0,1,1,1,1,1,1 },  // = G#
{ 1,1,1,0,1,1,1,0 },  // = A
{ 1,1,1,0,1,1,1,1 },  // = A#
{ 0,0,1,1,1,1,1,0 },  // = B
};


// Define the music notes for regular and sharp notes.
// Each separation is another octave
int g_notes[] =
{

//2
65,  //C
69,  //C#
73,  //D
78,  //D#
82,  //E
87,  //F
93,  //F#
98,  //G
104, //G#
110, //A
117, //A#
123, //B

//3
131,
139,
147,
156,
165,
175,
185,
196,
208,
220,
233,
247,

//4
262,
277,
294,
311,
330,
349,
370,
392,
415,
440,
466,
494,

//5
523,
554,
587,
622,
659,
698,
740,
784,
831,
880,
932,
988,

//6
1047,
1109,
1175,
1245,
1319,
1397,
1480,
1568,
1661,
1760,
1865,
1976,

//7
2093,
2217,
2349,
2489,
2637,
2794,
2960,
3136,
3322, 
3520,
3729,
3951,

};

//Constants
const int g_numNotesInOctave = 12;
const int g_noteOffset = g_numNotesInOctave*2;                          
const int g_numRecordableNotes = 32;
const int theNullNote = (g_numNotes-1);

const int ModeSwitchState_WaitingForPress = 0;
const int ModeSwitchState_WaitingForRelease = 1;
const int Mode_Recording = 0;
const int Mode_Playing = 1;

//Variables
int g_recordedNotes[g_numRecordableNotes];
int g_numNotesRecorded = 0;
int g_allowRecord = true;
int g_playBackIndex = 0;
int g_recordBleepTime = 100;
int g_noteLength = 200;
int g_modeSwitchState = ModeSwitchState_WaitingForPress;
int g_mode = Mode_Recording;

//Turns the 7 segment display's decimal point ON or OFF
void writeDot(byte dot)
{
	digitalWrite(10, dot);
}


//Write a single digit to the 7 segment display    
void sevenSegWriteDigit(byte digit)
{
	byte pin = 3;
	for (byte segCount = 0; segCount < 7; ++segCount)
	{
		digitalWrite(pin, seven_seg_digits[digit][segCount]);
		++pin;
	}
}


//Write a music note by index to the 7 segment display
void sevenSegWriteNote(byte noteIndex)
{
	byte pin = 3;
	for (byte segCount = 0; segCount < 8; ++segCount)
	{
		digitalWrite(pin, seven_seg_notes[noteIndex][segCount]);
		++pin;
	}
}


//This function runs once automatically at startup
void setup()
{  
	//These pins display the numbers/letters on the 7 segment LED display
	pinMode(3, OUTPUT);//Anode A
	pinMode(4, OUTPUT);//Anode B  
	pinMode(5, OUTPUT);//Anode C
	pinMode(6, OUTPUT);//Anode D
	pinMode(7, OUTPUT);//Anode E
	pinMode(8, OUTPUT);//Anode F
	pinMode(9, OUTPUT);//Anode G
	pinMode(10, OUTPUT);//Anode RHDP (right hand decimal place)

	//The blue LED flashes when an audible note is played
	pinMode(g_ledPin_Blue, OUTPUT);  // declare g_buttonPin2 as an OUTPUT

	//The green LED flashes when a silent note is played
	pinMode(g_ledPin_Green, OUTPUT);  // declare g_buttonPin2 as an OUTPUT

	//The pot controls note selection and song playback speed
	pinMode(g_potPin, INPUT);  // declare g_potPin as an INPUT

	//Button 1 is used to test notes before recording them
	pinMode(g_buttonPin1, INPUT);  // declare g_buttonPin1 as an INPUT

	//Button 2 is used to record notes
	pinMode(g_buttonPin2, INPUT);  // declare g_buttonPin2 as an INPUT

	//I am lazy and assume every pin starts out low
}


void ToggleMode()
{
	//Perform mode switch!
	if(g_mode == Mode_Playing)
	{
		//switch to Recording
		g_mode = Mode_Recording;

		//Init variables
		g_numNotesRecorded = 0;
		g_allowRecord = true;

		//Turn off the LEDs
		digitalWrite(g_ledPin_Blue, LOW);
		digitalWrite(g_ledPin_Green, LOW);
	}
	else
	{
		//Switch to Playing
		g_mode = Mode_Playing;

		//Init variables
		g_playBackIndex = 0;
	}
}


//This function loops automatically
void loop()
{
        // read the state of the pot
	int potVal = analogRead(g_potPin);    // read the value from the sensor
	float potFrac = 1.0f-(potVal/1023.0f);

	// read the state of the button value:
	int buttonState1 = digitalRead(g_buttonPin1);

	// read the state of the button value:
	int buttonState2 = digitalRead(g_buttonPin2);

        //Handle mode switching
        
        //If we are waiting for the two-button press
        if(g_modeSwitchState == ModeSwitchState_WaitingForPress)
        {
            //If you press both buttons, then wait for release
            if( buttonState1 == HIGH
	          && buttonState2 == HIGH)
			{
				g_modeSwitchState = ModeSwitchState_WaitingForRelease;
				
				ToggleMode();
			}
        }
        //If we are waiting for button release
        else
        {
            //Switch modes when both of the two buttons are released
            if( buttonState1 == LOW
	          && buttonState2 == LOW)
            {
                //Now we will be waiting for a press again
                g_modeSwitchState = ModeSwitchState_WaitingForPress;
            }
            
            //Return early until released
            return;
        }
        
	//Play mode
	if(g_mode == Mode_Playing)
	{
		//If there are no notes, do nothing
		if(g_numNotesRecorded == 0)
		{
		  return;
		}

		int theNote = g_recordedNotes[g_playBackIndex];
		
		//Display current note
		sevenSegWriteNote(theNote);
		
		if(theNote == theNullNote)
		{
			tone(g_buzzerPin,0,g_noteLength);
		}
		else
		{ 
			tone(g_buzzerPin,g_notes[theNote+g_noteOffset],g_noteLength);
		}

		//Turn on the blue LED for any note
		digitalWrite(g_ledPin_Blue, HIGH);

		//Turn on the green LED for sharp notes
		if(theNote == theNullNote)
		{
			digitalWrite(g_ledPin_Green, HIGH);
		}

		//Small delay to allow the LEDs to remain lit
		delay(50);

		//Turn off both LEDs
		digitalWrite(g_ledPin_Blue, LOW);
		digitalWrite(g_ledPin_Green, LOW);

		//Delay between each note
		delay(500*(1.0f-potFrac));
		
		//Turn off the music note when done
		noTone(g_buzzerPin);

		//Now to play the next note!
		++g_playBackIndex;
		
		//Wrap the index
		if(g_playBackIndex == g_numNotesRecorded)
		{
			g_playBackIndex = 0;
		}
	}
	//Record mode
	else
	{
		//Calculate which note index we should be playing
		int potBasedNote = potFrac*(g_numNotes-1) + 0.5f;

		//Display the note
		sevenSegWriteNote(potBasedNote);

		//Test the note before recording
		if(buttonState1 == HIGH)
		{
			if(potBasedNote != theNullNote)
			{
				tone(g_buzzerPin,g_notes[potBasedNote+g_noteOffset],100);
			}
		}
		else
		{
			noTone(g_buzzerPin);
		}

		//Record the note on button press
		if(g_allowRecord && (buttonState2 == HIGH && buttonState1 == LOW))
		{
			if(potBasedNote == theNullNote)
			{
				digitalWrite(g_ledPin_Green, HIGH);
			}
			else
			{
				digitalWrite(g_ledPin_Blue, HIGH);
				tone(g_buzzerPin,g_notes[potBasedNote+g_noteOffset],g_recordBleepTime);
			}

			//Delay to allow the note you just recorded to play briefly
			delay(g_recordBleepTime);
			noTone(g_buzzerPin);
			
			//Turn off the LEDs
			digitalWrite(g_ledPin_Blue, LOW);
			digitalWrite(g_ledPin_Green, LOW);

			//Record the note!
			g_recordedNotes[g_numNotesRecorded] = potBasedNote;
			++g_numNotesRecorded;

			g_allowRecord = false;

			//End song early
			if( g_numNotesRecorded == g_numRecordableNotes )
			{
			  ToggleMode();
			}
		}
		else if(buttonState2 == LOW)
		{
			g_allowRecord = true;
		}
	}
}