06 - Lab Music Studio

# Lab: **Music Studio - Record, Edit & Play Your Own Compositions** ## **Objective** Create an advanced music composition system using the TK37 passive buzzer with recording, editing, and playback capabilities. Learn to implement complex data structures, real-time recording, and professional music composition features. ## **Required Components** ![](https://cdn.shopify.com/s/files/1/0331/9994/7908/files/Pasted_image_20250723155115.png?v=1753858090) 1. **Lonely Binary UNO R3** - Main Arduino board 2. **TinkerBlock UNO R3 Shield** - Expansion shield that plugs onto the UNO R3 3. **TinkerBlock TK37** - Passive Buzzer Module ## **Theory** ### **Music Composition Systems** - **Real-time Recording**: Capture musical input as it's created - **Data Structures**: Organize musical data efficiently - **Editing Capabilities**: Modify and refine compositions - **Playback Control**: Professional music playback features ### **Advanced Data Management** - **Note Structures**: Store frequency, duration, and velocity - **Composition Storage**: Manage multiple musical pieces - **Memory Optimization**: Efficient use of limited Arduino memory - **State Persistence**: Maintain composition data across sessions ### **Professional Music Features** - **Tempo Control**: Adjustable playback speed - **Loop Mode**: Continuous playback options - **Composition Editing**: Insert, delete, and modify notes - **Status Management**: Track recording and playback states ## **Wiring Instructions** ### **TK37 Passive Buzzer Pinout** - **GND** → Arduino GND - **VCC** → Arduino 5V - **NC** → No Connection - **Signal** → Arduino Digital Pin D9 ### **Connection Diagram** ![](https://cdn.shopify.com/s/files/1/0331/9994/7908/files/Pasted_image_20250723155152.png?v=1753858122) ``` UNO R3 + Shield └── Digital Pin D9 ──→ TK37 Signal ``` ## **Advanced Music Composer** ```cpp // Advanced Music Composer with TK37 Passive Buzzer // Pin definitions #define BUZZER_PIN 9 // Musical note frequencies (extended set) #define NOTE_C3 131 #define NOTE_CS3 139 #define NOTE_D3 147 #define NOTE_DS3 156 #define NOTE_E3 165 #define NOTE_F3 175 #define NOTE_FS3 185 #define NOTE_G3 196 #define NOTE_GS3 208 #define NOTE_A3 220 #define NOTE_AS3 233 #define NOTE_B3 247 #define NOTE_C4 262 #define NOTE_CS4 277 #define NOTE_D4 294 #define NOTE_DS4 311 #define NOTE_E4 330 #define NOTE_F4 349 #define NOTE_FS4 370 #define NOTE_G4 392 #define NOTE_GS4 415 #define NOTE_A4 440 #define NOTE_AS4 466 #define NOTE_B4 494 #define NOTE_C5 523 #define NOTE_CS5 554 #define NOTE_D5 587 #define NOTE_DS5 622 #define NOTE_E5 659 #define NOTE_F5 698 #define NOTE_FS5 740 #define NOTE_G5 784 #define NOTE_GS5 831 #define NOTE_A5 880 #define NOTE_AS5 932 #define NOTE_B5 988 #define NOTE_C6 1047 #define NOTE_CS6 1109 #define NOTE_D6 1175 #define NOTE_DS6 1245 #define NOTE_E6 1319 #define NOTE_F6 1397 #define NOTE_FS6 1480 #define NOTE_G6 1568 #define NOTE_GS6 1661 #define NOTE_A6 1760 #define NOTE_AS6 1865 #define NOTE_B6 1976 // Note duration constants #define WHOLE_NOTE 1600 #define HALF_NOTE 800 #define QUARTER_NOTE 400 #define EIGHTH_NOTE 200 #define SIXTEENTH_NOTE 100 #define THIRTY_SECOND_NOTE 50 // Rest note #define REST 0 // Music composition structure struct Note { int frequency; int duration; int velocity; // 0-127 for volume simulation }; // Composition storage #define MAX_COMPOSITION_LENGTH 100 Note composition[MAX_COMPOSITION_LENGTH]; int compositionLength = 0; int currentPosition = 0; // Player states #define STATE_STOPPED 0 #define STATE_PLAYING 1 #define STATE_PAUSED 2 #define STATE_RECORDING 3 int playerState = STATE_STOPPED; int tempo = 120; // BPM bool loopMode = false; void setup() { Serial.begin(9600); pinMode(BUZZER_PIN, OUTPUT); delay(1000); Serial.println("TK37 Advanced Music Composer"); Serial.println("============================"); Serial.println("Commands:"); Serial.println("r: Start recording"); Serial.println("s: Stop recording/playback"); Serial.println("p: Play composition"); Serial.println("c: Clear composition"); Serial.println("l: Toggle loop mode"); Serial.println("+: Increase tempo"); Serial.println("-: Decrease tempo"); Serial.println("i: Insert note"); Serial.println("d: Delete note"); Serial.println("v: View composition"); Serial.println("?: Show help"); Serial.println(); displayComposerStatus(); } void loop() { if (Serial.available()) { char command = Serial.read(); handleComposerCommand(command); } // Handle playback if playing if (playerState == STATE_PLAYING) { playNextNote(); } delay(10); } void handleComposerCommand(char command) { switch (command) { case 'r': startRecording(); break; case 's': stopAction(); break; case 'p': startPlayback(); break; case 'c': clearComposition(); break; case 'l': toggleLoopMode(); break; case '+': increaseTempo(); break; case '-': decreaseTempo(); break; case 'i': insertNote(); break; case 'd': deleteNote(); break; case 'v': viewComposition(); break; case '?': showComposerHelp(); break; } } void startRecording() { if (playerState == STATE_RECORDING) { Serial.println("Already recording!"); return; } playerState = STATE_RECORDING; compositionLength = 0; Serial.println("Recording started. Enter notes:"); Serial.println("Format: frequency,duration (e.g., 440,400)"); Serial.println("Enter 'stop' to end recording"); } void stopAction() { if (playerState == STATE_RECORDING) { playerState = STATE_STOPPED; Serial.print("Recording stopped. Composition length: "); Serial.println(compositionLength); } else if (playerState == STATE_PLAYING) { playerState = STATE_STOPPED; noTone(BUZZER_PIN); Serial.println("Playback stopped"); } } void startPlayback() { if (compositionLength == 0) { Serial.println("No composition to play!"); return; } playerState = STATE_PLAYING; currentPosition = 0; Serial.println("Starting playback..."); } void clearComposition() { compositionLength = 0; currentPosition = 0; Serial.println("Composition cleared"); } void toggleLoopMode() { loopMode = !loopMode; Serial.print("Loop mode: "); Serial.println(loopMode ? "ON" : "OFF"); } void increaseTempo() { tempo += 10; if (tempo > 200) tempo = 200; Serial.print("Tempo: "); Serial.print(tempo); Serial.println(" BPM"); } void decreaseTempo() { tempo -= 10; if (tempo < 60) tempo = 60; Serial.print("Tempo: "); Serial.print(tempo); Serial.println(" BPM"); } void insertNote() { if (compositionLength >= MAX_COMPOSITION_LENGTH) { Serial.println("Composition full!"); return; } Serial.println("Enter frequency (20-20000 Hz):"); while (!Serial.available()) delay(100); int frequency = Serial.parseInt(); Serial.println("Enter duration (ms):"); while (!Serial.available()) delay(100); int duration = Serial.parseInt(); if (frequency >= 20 && frequency <= 20000 && duration > 0) { composition[compositionLength].frequency = frequency; composition[compositionLength].duration = duration; composition[compositionLength].velocity = 100; compositionLength++; Serial.print("Note added: "); Serial.print(frequency); Serial.print(" Hz, "); Serial.print(duration); Serial.println(" ms"); } else { Serial.println("Invalid values!"); } } void deleteNote() { if (compositionLength == 0) { Serial.println("No notes to delete!"); return; } Serial.print("Enter note position (0-"); Serial.print(compositionLength - 1); Serial.println("):"); while (!Serial.available()) delay(100); int position = Serial.parseInt(); if (position >= 0 && position < compositionLength) { // Shift remaining notes for (int i = position; i < compositionLength - 1; i++) { composition[i] = composition[i + 1]; } compositionLength--; Serial.println("Note deleted"); } else { Serial.println("Invalid position!"); } } void viewComposition() { if (compositionLength == 0) { Serial.println("No composition to view"); return; } Serial.println("Composition:"); Serial.println("Pos | Freq(Hz) | Duration(ms)"); Serial.println("----|----------|-------------"); for (int i = 0; i < compositionLength; i++) { Serial.print(i); Serial.print(" | "); Serial.print(composition[i].frequency); Serial.print(" | "); Serial.println(composition[i].duration); } Serial.println(); } void playNextNote() { if (currentPosition >= compositionLength) { if (loopMode) { currentPosition = 0; Serial.println("Looping composition..."); } else { playerState = STATE_STOPPED; noTone(BUZZER_PIN); Serial.println("Playback complete"); return; } } Note currentNote = composition[currentPosition]; int adjustedDuration = currentNote.duration * 120 / tempo; if (currentNote.frequency == REST) { delay(adjustedDuration); } else { tone(BUZZER_PIN, currentNote.frequency, adjustedDuration); delay(adjustedDuration + 50); } currentPosition++; } void showComposerHelp() { Serial.println("Advanced Music Composer Help:"); Serial.println("r: Start recording new composition"); Serial.println("s: Stop recording or playback"); Serial.println("p: Play current composition"); Serial.println("c: Clear composition"); Serial.println("l: Toggle loop mode"); Serial.println("+/-: Adjust tempo"); Serial.println("i: Insert note manually"); Serial.println("d: Delete note"); Serial.println("v: View composition"); Serial.println("Recording format: frequency,duration"); Serial.println("Example: 440,400 (A4 note, 400ms)"); Serial.println(); } void displayComposerStatus() { Serial.println("Composer Status:"); Serial.print("State: "); switch (playerState) { case STATE_STOPPED: Serial.println("STOPPED"); break; case STATE_PLAYING: Serial.println("PLAYING"); break; case STATE_PAUSED: Serial.println("PAUSED"); break; case STATE_RECORDING: Serial.println("RECORDING"); break; } Serial.print("Tempo: "); Serial.print(tempo); Serial.println(" BPM"); Serial.print("Loop: "); Serial.println(loopMode ? "ON" : "OFF"); Serial.print("Notes: "); Serial.println(compositionLength); Serial.println(); } ``` ## **Code Explanation** ### **Advanced Data Structure** ```cpp struct Note { int frequency; int duration; int velocity; // 0-127 for volume simulation }; ``` - **Professional Structure**: Mimics MIDI note structure - **Frequency Storage**: Musical note frequency in Hz - **Duration Control**: Note length in milliseconds - **Velocity Support**: Volume control (0-127 range) ### **Composition Management** ```cpp #define MAX_COMPOSITION_LENGTH 100 Note composition[MAX_COMPOSITION_LENGTH]; int compositionLength = 0; int currentPosition = 0; ``` - **Memory Management**: Fixed array size for stability - **Dynamic Length**: Tracks actual composition size - **Position Tracking**: Current playback position - **Efficient Storage**: Compact note representation ### **State Management System** ```cpp #define STATE_STOPPED 0 #define STATE_PLAYING 1 #define STATE_PAUSED 2 #define STATE_RECORDING 3 int playerState = STATE_STOPPED; ``` - **Four States**: Comprehensive state management - **STOPPED**: System idle, ready for commands - **PLAYING**: Currently playing composition - **PAUSED**: Playback paused, can resume - **RECORDING**: Capturing new composition ### **Recording System** ```cpp void startRecording() { if (playerState == STATE_RECORDING) { Serial.println("Already recording!"); return; } playerState = STATE_RECORDING; compositionLength = 0; Serial.println("Recording started. Enter notes:"); Serial.println("Format: frequency,duration (e.g., 440,400)"); Serial.println("Enter 'stop' to end recording"); } ``` - **State Validation**: Prevents multiple recording sessions - **Memory Reset**: Clears previous composition - **User Guidance**: Clear instructions for input format - **Error Prevention**: Checks for valid recording state ### **Note Insertion System** ```cpp void insertNote() { if (compositionLength >= MAX_COMPOSITION_LENGTH) { Serial.println("Composition full!"); return; } Serial.println("Enter frequency (20-20000 Hz):"); while (!Serial.available()) delay(100); int frequency = Serial.parseInt(); Serial.println("Enter duration (ms):"); while (!Serial.available()) delay(100); int duration = Serial.parseInt(); if (frequency >= 20 && frequency <= 20000 && duration > 0) { composition[compositionLength].frequency = frequency; composition[compositionLength].duration = duration; composition[compositionLength].velocity = 100; compositionLength++; Serial.print("Note added: "); Serial.print(frequency); Serial.print(" Hz, "); Serial.print(duration); Serial.println(" ms"); } else { Serial.println("Invalid values!"); } } ``` - **Memory Protection**: Checks for available space - **Input Validation**: Ensures frequency and duration are valid - **User Feedback**: Confirms successful note addition - **Error Handling**: Reports invalid input values ### **Note Deletion System** ```cpp void deleteNote() { if (compositionLength == 0) { Serial.println("No notes to delete!"); return; } Serial.print("Enter note position (0-"); Serial.print(compositionLength - 1); Serial.println("):"); while (!Serial.available()) delay(100); int position = Serial.parseInt(); if (position >= 0 && position < compositionLength) { // Shift remaining notes for (int i = position; i < compositionLength - 1; i++) { composition[i] = composition[i + 1]; } compositionLength--; Serial.println("Note deleted"); } else { Serial.println("Invalid position!"); } } ``` - **Array Management**: Shifts remaining notes to fill gap - **Position Validation**: Ensures valid note position - **Memory Optimization**: Reduces composition length - **User Feedback**: Confirms deletion action ### **Playback System** ```cpp void playNextNote() { if (currentPosition >= compositionLength) { if (loopMode) { currentPosition = 0; Serial.println("Looping composition..."); } else { playerState = STATE_STOPPED; noTone(BUZZER_PIN); Serial.println("Playback complete"); return; } } Note currentNote = composition[currentPosition]; int adjustedDuration = currentNote.duration * 120 / tempo; if (currentNote.frequency == REST) { delay(adjustedDuration); } else { tone(BUZZER_PIN, currentNote.frequency, adjustedDuration); delay(adjustedDuration + 50); } currentPosition++; } ``` - **Loop Support**: Continuous playback when enabled - **Tempo Scaling**: Adjusts duration based on current tempo - **REST Handling**: Supports silence periods - **Position Advancement**: Moves to next note automatically ### **Composition Viewing** ```cpp void viewComposition() { if (compositionLength == 0) { Serial.println("No composition to view"); return; } Serial.println("Composition:"); Serial.println("Pos | Freq(Hz) | Duration(ms)"); Serial.println("----|----------|-------------"); for (int i = 0; i < compositionLength; i++) { Serial.print(i); Serial.print(" | "); Serial.print(composition[i].frequency); Serial.print(" | "); Serial.println(composition[i].duration); } Serial.println(); } ``` - **Tabular Display**: Organized composition view - **Position Indexing**: Shows note positions - **Complete Information**: Frequency and duration for each note - **Professional Format**: Clean, readable output ### **Advanced Features** #### **Tempo Control** ```cpp void increaseTempo() { tempo += 10; if (tempo > 200) tempo = 200; Serial.print("Tempo: "); Serial.print(tempo); Serial.println(" BPM"); } ``` - **Incremental Adjustment**: 10 BPM changes - **Range Limiting**: 60-200 BPM for musical practicality - **Real-time Display**: Shows current tempo - **Playback Integration**: Affects all note durations #### **Loop Mode** ```cpp void toggleLoopMode() { loopMode = !loopMode; Serial.print("Loop mode: "); Serial.println(loopMode ? "ON" : "OFF"); } ``` - **Toggle Functionality**: Switches between loop states - **Status Display**: Shows current loop setting - **Playback Integration**: Enables continuous playback - **User Control**: Manual loop control ### **Professional Music Features** - **Note Structure**: Professional-grade note representation - **Composition Management**: Full composition lifecycle - **Editing Capabilities**: Insert, delete, and modify notes - **Playback Control**: Professional playback features - **Status Management**: Comprehensive system status tracking ## **Expected Output** ### **Serial Monitor Output** ``` TK37 Advanced Music Composer ============================ Commands: r: Start recording s: Stop recording/playback p: Play composition c: Clear composition l: Toggle loop mode +: Increase tempo -: Decrease tempo i: Insert note d: Delete note v: View composition ?: Show help Composer Status: State: STOPPED Tempo: 120 BPM Loop: OFF Notes: 0 > r Recording started. Enter notes: Format: frequency,duration (e.g., 440,400) Enter 'stop' to end recording > i Enter frequency (20-20000 Hz): 440 Enter duration (ms): 400 Note added: 440 Hz, 400 ms > v Composition: Pos | Freq(Hz) | Duration(ms) ----|----------|------------- 0 | 440 | 400 > p Starting playback... ``` ### **Audio Output** - **Individual Notes**: Clear, precise note playback - **Composition Playback**: Complete musical pieces - **Tempo Variations**: Noticeable speed changes - **Loop Playback**: Continuous composition repetition - **Professional Quality**: High-quality musical output ### **Interactive Behavior** - **Real-time Recording**: Immediate note capture - **Dynamic Editing**: Live composition modification - **Professional Control**: Advanced playback features - **Status Awareness**: Complete system status tracking - **Error Handling**: Robust error management ## **Troubleshooting** ### **Recording issues:** - **Memory Full**: Composition exceeds 100 notes - **Input Format**: Ensure frequency,duration format - **Range Validation**: Frequency 20-20000 Hz, duration > 0 - **State Conflicts**: Check recording state ### **Playback problems:** - **Empty Composition**: No notes to play - **Tempo Issues**: Check tempo range (60-200 BPM) - **Loop Conflicts**: Verify loop mode settings - **Memory Issues**: Large compositions may cause problems ### **Editing difficulties:** - **Position Errors**: Note position out of range - **Array Management**: Check composition length - **Memory Allocation**: Verify available memory - **State Conflicts**: Ensure proper editing state ### **System state issues:** - **State Confusion**: Check current player state - **Command Conflicts**: Verify command compatibility - **Memory Corruption**: Check for memory issues - **Timing Problems**: Verify delay and timing functions ### **Audio quality problems:** - **Wiring Issues**: Check TK37 connections - **Power Supply**: Ensure stable 5V power - **Frequency Range**: Test with different frequencies - **Buzzer Quality**: Verify TK37 module functionality ## **Applications** ### **Educational** - **Music Composition**: Learn musical composition principles - **Data Structures**: Understanding complex data organization - **Real-time Systems**: Interactive programming concepts - **Professional Development**: Industry-standard music systems ### **Professional** - **Music Production**: Prototype musical compositions - **Audio Engineering**: Test audio system concepts - **Product Development**: Audio product prototyping - **Research**: Musical algorithm development ### **Entertainment** - **Interactive Music**: User-created musical experiences - **Game Development**: Dynamic music systems - **Performance Art**: Live composition systems - **Musical Instruments**: Digital instrument development ### **Commercial** - **Product Testing**: Audio system validation - **User Experience**: Audio interaction testing - **Prototyping**: Quick audio system development - **Integration Testing**: Audio system integration ## **Customization Ideas** ### **Add Advanced Features:** - **MIDI Integration**: Connect to MIDI devices - **SD Card Storage**: Save compositions to memory card - **Network Control**: Remote control via WiFi/Bluetooth - **Visual Interface**: LCD display for composition view ### **Enhance Musical Capabilities:** - **Harmony Support**: Multiple simultaneous notes - **Effects Processing**: Reverb, echo, and other effects - **Instrument Simulation**: Different instrument sounds - **Advanced Timing**: Complex rhythmic patterns ### **Improve User Interface:** - **Graphical Display**: Visual composition editor - **Touch Interface**: Touch-sensitive controls - **Voice Commands**: Voice-activated composition - **Gesture Control**: Motion-based composition ### **Add Professional Features:** - **Score Generation**: Create musical notation - **Export Functions**: Save in various audio formats - **Collaboration Tools**: Multi-user composition - **Cloud Integration**: Online composition sharing ## **Next Steps** - **Study Music Theory**: Advanced musical composition - **Learn Data Structures**: Complex data organization - **Explore Audio Processing**: Digital signal processing - **Investigate MIDI**: Professional music protocols - **Build Complete Systems**: Full music production systems ## **Resources** - **Music Composition**: Advanced musical composition techniques - **Data Structures**: Complex data organization principles - **Real-time Systems**: Interactive system design - **Audio Engineering**: Professional audio processing - **MIDI Protocol**: Standard music industry protocols

RELATED ARTICLES