# 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
£25.00 GBP
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.