# 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**

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**

```
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 
                                
                            
                            06 - Lab Music Studio
RELATED ARTICLES
04 - Lab IR Battle Game
03 - Lab Invisible Guardian
02 - TK64 Infrared Receiver
01 - TK63 Infrared Transmitter
03 - Lab Disco Light Master
02 - Lab Sound Detection Master
04 - Lab Sound Alert Defender
 
	   
	 
	   
	 
	   
	 
	   
	 
	   
	 
	   
	 
	   
	TinkerBlock UNO R3 Starter Kit
     No reviews  
 Dive into the world of electronics, Arduino programming, and STEM projects with the Lonely Binary TinkerBlock Series Starter Kit. 
- Choosing a selection results in a full page refresh.


