Skip to content

Commit d101fa2

Browse files
committed
adjust theremin readme content
1 parent 03838cd commit d101fa2

File tree

1 file changed

+89
-74
lines changed

1 file changed

+89
-74
lines changed

examples/theremin/README.md

Lines changed: 89 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -2,73 +2,79 @@
22

33
The **Theremin Simulator** example lets you create and control a virtual theremin instrument using an interactive web interface, producing synthesized audio output through a connected **USB** audio device with low latency.
44

5-
> **Note**: This example must be run in **[Network Mode](learn/network-mode)** or **[SBC Mode](learn/single-board-computer)**, since it requires a **USB-C® hub** and a **USB speaker**.
5+
**Note:** This example requires to be run using **[Network Mode](learn/network-mode)** or **[Single-Board Computer (SBC) Mode](learn/single-board-computer)**, since it requires a **USB-C® hub** and a **USB speaker**.
66

77
![Theremin Simulator](assets/docs_assets/theremin-simulator.png)
88

9-
This example generates real-time audio by creating sine waves at varying frequencies and amplitudes based on user input from the web interface. The workflow involves receiving mouse/touch coordinates from the frontend and updating a **Wave Generator** Brick, which handles the audio synthesis, smoothing, and streaming to the USB device automatically.
9+
This App creates a virtual instrument that generates real-time audio by creating sine waves at varying frequencies and amplitudes based on user input. The workflow involves receiving mouse or touch coordinates from the frontend and updating a **Wave Generator** Brick, which handles the audio synthesis, smoothing, and streaming to the **USB device** automatically.
10+
11+
Key features include:
12+
13+
- Real-time audio synthesis with low latency
14+
- Interactive web interface for pitch and volume control
15+
- Visual waveform display showing frequency and amplitude
16+
- Automatic envelope smoothing (attack, release, glide) for natural sound
17+
- Support for USB speakers and wireless USB audio receivers
1018

1119
## Bricks Used
1220

21+
The theremin simulator example uses the following Bricks:
22+
1323
- `web_ui`: Brick that provides the web interface and a WebSocket channel for real-time control of the theremin.
1424
- `wave_generator`: Brick that handles audio synthesis, envelope control (smoothing), and streaming to the USB audio device.
1525

1626
## Hardware and Software Requirements
1727

1828
### Hardware
1929

20-
- [Arduino UNO Q](https://store.arduino.cc/products/uno-q) (x1)
30+
- Arduino UNO Q (x1)
2131
- **USB-C® hub with external power (x1)**
2232
- A power supply (5 V, 3 A) for the USB hub (x1)
2333
- A **USB audio device** (choose one):
24-
- **USB speaker** (cabled) ✅ *supported*
25-
- **USB wireless speaker receiver/dongle** (2.4 GHz, non-Bluetooth) ✅ *supported*
26-
- **USB‑C → 3.5 mm audio connector** + headphones/speakers ⚠️ *not tested* (may work)
34+
- **USB speaker** (cabled)
35+
- **USB wireless speaker receiver/dongle** (2.4 GHz, non-Bluetooth)
2736
- A **power supply** (5 V, 3 A) for the USB hub (e.g. a phone charger)
2837

29-
> **Not supported:** **HDMI audio** and **Bluetooth® Speakers** are not supported by this App.
30-
3138
### Software
3239

3340
- Arduino App Lab
3441

35-
**Note:** A **USB-C® hub is mandatory** for this example. The UNO Q's single port must be used for the hub, which provides the necessary connections for both the power supply and the USB audio device. consequently, this example must be run in **[Network Mode](learn/network-mode)** or **[SBC Mode](learn/single-board-computer)**.
42+
**Important:** A **USB-C® hub is mandatory** for this example. The UNO Q's single port must be used for the hub, which provides the necessary connections for both the power supply and the USB audio device. Consequently, this example must be run in **[Network Mode](learn/network-mode)** or **[SBC Mode](learn/single-board-computer)**.
43+
44+
**Note:** **HDMI audio** and **Bluetooth® Speakers** are not supported by this App.
3645

3746
## How to Use the Example
3847

39-
1. **Hardware Setup:** Connect your **USB audio device** (e.g., USB speaker, wireless USB receiver) to a powered **USB-C® hub** attached to the UNO Q.
40-
![hardware-setup](assets/docs_assets/hardware-setup.png)
48+
1. **Hardware Setup**
49+
Connect your **USB audio device** (e.g., USB speaker, wireless USB receiver) to a powered **USB-C® hub** attached to the UNO Q. Ensure the hub is powered.
4150

42-
2. **Launch:** Launch the App by clicking the **Play** button in the top-right corner. Wait until the App has launched.
43-
![Launching an App](assets/docs_assets/launch-app-theremin.png)
51+
2. **Run the App**
52+
Launch the App from Arduino App Lab. Wait until the App has launched completely.
4453

45-
3. **Open Interface:** Open the App in your browser at `<UNO-Q-IP-ADDRESS>:7000` *(typically 192.168.x.x, e.g., http://192.168.1.11:7000)*.
54+
3. **Access the Web Interface**
55+
Open the App in your browser at `<UNO-Q-IP-ADDRESS>:7000` (typically `192.168.x.x`).
4656

47-
### Interacting with the Interface
57+
4. **Turn on Power**
58+
Locate the orange control panel at the bottom of the interface. Click the **POWER** switch to toggle it **ON** (the small LED indicator will light up).
59+
*Note: No sound will be produced if this switch is OFF.*
4860

49-
Once the web page loads, follow these steps to make sound:
61+
5. **Set Master Volume**
62+
Use the **+** and **-** buttons near the **VOL** indicator to adjust the master volume. This sets the maximum output limit for the application.
5063

51-
1. **Turn on Power:** Locate the orange control panel at the bottom. Click the **POWER** switch to toggle it **ON** (the small LED indicator will light up).
52-
* *Note: No sound will be produced if this switch is OFF.*
53-
2. **Set Master Volume:** Adjust the **VOL** knob to a comfortable level (e.g., 70-80%). This sets the maximum output limit for the application.
54-
3. **Play the Instrument:** Drag your mouse (or use your finger on a touchscreen) inside the large gray background area:
55-
* **Horizontal (Left ↔ Right):** Controls **Pitch**. Moving right increases the frequency (higher notes).
56-
* **Vertical (Bottom ↕ Top):** Controls **Note Volume**. Moving up increases the amplitude (louder). Moving to the very bottom silences the note.
57-
4. **Waveform Display:** The screen in the center of the panel visualizes the real-time sine wave, frequency (Hz), and amplitude data.
64+
6. **Play the Instrument**
65+
Drag your mouse (or use your finger on a touchscreen) inside the large gray background area:
66+
- **Horizontal (Left ↔ Right):** Controls **Pitch**. Moving right increases the frequency (higher notes).
67+
- **Vertical (Bottom ↕ Top):** Controls **Note Volume**. Moving up increases the amplitude (louder). Moving to the very bottom silences the note.
5868

59-
#### Additional Controls
60-
* **GRID Switch:** Toggles a background grid overlay. Use this to visually reference specific pitch intervals or volume levels.
69+
7. **Visualize Audio**
70+
Observe the screen in the center of the panel, which visualizes the real-time sine wave, frequency (Hz), and amplitude data. You can also toggle the **GRID** switch to visually reference specific pitch intervals.
6171

6272
## How it Works
6373

64-
The application uses the `wave_generator` Brick to create a continuous audio stream. The Python backend receives user coordinates via WebSocket and updates the generator's frequency and amplitude. The Brick automatically handles **envelope smoothing** (attack, release, glide) to ensure the audio changes sound natural and analog-like, rather than robotic.
65-
66-
- **User Interaction**: The frontend captures mouse/touch coordinates and sends them to the backend.
67-
- **Real-time Communication**: Input data is sent via the `web_ui` Brick's WebSocket channel.
68-
- **Audio Synthesis**: The `wave_generator` Brick runs in the background. It takes the target frequency and amplitude and applies a **glide algorithm** to transition smoothly between notes.
69-
- **Audio Output**: The Brick streams the generated sine wave directly to the **USB** audio device.
74+
The application relies on a continuous data pipeline between the web interface and the audio synthesis engine.
7075

7176
**High-level data flow:**
77+
7278
```
7379
Web Browser Interaction ──► WebSocket ──► Python Backend
7480
▲ │
@@ -81,71 +87,80 @@ Web Browser Interaction ──► WebSocket ──► Python Backend
8187
USB Audio Output
8288
```
8389

90+
- **User Interaction**: The frontend captures mouse/touch coordinates and sends them to the backend via the `web_ui` Brick's WebSocket channel.
91+
- **Audio Synthesis**: The `wave_generator` Brick runs in the background. It takes the target frequency and amplitude and applies a **glide algorithm** to transition smoothly between notes.
92+
- **Envelope Smoothing**: The Brick automatically handles attack, release, and glide to ensure the audio changes sound natural and analog-like, rather than robotic.
93+
- **Audio Output**: The Brick streams the generated sine wave directly to the **USB** audio device.
8494

8595
## Understanding the Code
8696

8797
### 🔧 Backend (`main.py`)
8898

89-
The Python code is simplified by using the `WaveGenerator` Brick, which encapsulates the audio logic.
99+
The Python script simplifies audio logic by utilizing the `WaveGenerator` Brick.
90100

91-
- `wave_gen = WaveGenerator(...)` – Initializes the audio engine. It configures the **wave type** (sine), **sample rate** (16kHz), and **envelope parameters** (attack, release, glide). This Brick automatically connects to the USB audio device and starts a background thread for streaming.
92-
- `ui.on_message('theremin:move', on_move)` – When the frontend sends new coordinates, this function calculates the target frequency and calls `wave_gen.set_frequency()` and `wave_gen.set_amplitude()`.
93-
- `App.run()` – Starts the application. Since the audio generation is handled by the Brick in the background, no custom loop is required here.
101+
- **Initialization**: Configures the audio engine with specific parameters (sine wave, 16kHz sample rate) and envelope settings (attack, release, glide).
102+
- **Frequency Calculation**: Maps the X-axis input (0.0 to 1.0) exponentially to a frequency range of 20 Hz to ~8000 Hz.
103+
- **Event Handling**: Listens for `theremin:move` events from the frontend to update frequency and amplitude.
94104

95-
### 💻 Frontend (`main.js`)
105+
```python
106+
wave_gen = WaveGenerator(sample_rate=16000, ...)
96107

97-
The web interface provides the interactive play area and controls for the user.
108+
def _freq_from_x(x):
109+
# Exponential mapping from 20Hz up to Nyquist frequency
110+
return 20.0 * ((SAMPLE_RATE / 2.0 / 20.0) ** x)
98111

99-
- **Socket.IO connection** to the backend to send and receive data in real time.
100-
- **Event listeners** capture `mousedown`, `mousemove`, `mouseup` (and touch equivalents) to track user interaction in the play area.
101-
- `socket.emit('theremin:move', { x, y })` – Sends normalized (0.0–1.0) X and Y coordinates to the backend; emissions are **throttled to ~80 Hz (≈12 ms)** to avoid overload.
102-
- `socket.on('theremin:state', ...)` – Receives state updates from the backend (like the calculated frequency and amplitude) and updates the values displayed on the webpage.
103-
- **Visual Waveform Generation:** Using the amplitude and frequency data received from the backend, the frontend draws a real-time sine wave animation on the HTML Canvas, providing immediate visual feedback.
104-
- `socket.emit('theremin:set_volume', { volume })` – Sends a **0–100** master volume value.
105-
- `socket.emit('theremin:power', { on })` – Toggles synth power (**On/Off**).
112+
def on_move(sid, data):
113+
# Calculate target frequency and amplitude based on coordinates
114+
freq = _freq_from_x(data.get("x"))
115+
amp = max(0.0, min(1.0, 1.0 - float(data.get("y"))))
116+
117+
wave_gen.set_frequency(freq)
118+
wave_gen.set_amplitude(amp)
119+
```
106120

107-
## Troubleshooting
121+
### 🔧 Frontend (`main.js`)
108122

109-
### "No USB speaker found" error
123+
The web interface handles user input and visualization.
110124

111-
If the application fails to start and you see an error regarding the speaker (e.g., inside the `WaveGenerator` initialization), it means the required audio hardware is missing.
125+
- **Input Capture**: Event listeners track `mousemove`, `touchmove`, and `touchstart` to capture user interaction.
126+
- **Throttling**: Emissions to the backend are throttled to approximately 80 Hz (~12 ms) to prevent network overload while maintaining responsiveness.
127+
- **Visual Feedback**: The canvas draws a real-time sine wave animation based on the amplitude and frequency data received back from the server.
128+
129+
```javascript
130+
// Send normalized coordinates (0.0 - 1.0) to backend
131+
socket.emit('theremin:move', { x, y });
132+
133+
// Receive state for visualization
134+
socket.on('theremin:state', (data) => {
135+
updateStateDisplay(data.freq, data.amp);
136+
});
137+
```
112138

139+
## Troubleshooting
140+
141+
### "No USB speaker found" error
142+
If the application fails to start and you see an error regarding the speaker:
113143
**Fix:**
114-
1. Make sure a **powered USB-C® hub** is connected to the UNO Q and its **5 V / 3 A** power supply is plugged in.
115-
2. Verify the **USB audio device** (USB speaker or wireless USB receiver) is **connected to the hub** and, if it has a switch, **turned on**.
144+
1. Ensure a **powered USB-C® hub** is connected to the UNO Q.
145+
2. Verify the **USB audio device** is connected to the hub and turned on.
116146
3. Restart the application.
117147

118148
### No Sound Output
119-
120-
- **Power Button:** Make sure the button in the web UI shows **On**.
121-
- **Volume Knob:** Check the visual knob on the web UI.
122-
- **Pointer Position:** Move your mouse/finger toward the top of the play area (the bottom corresponds to zero volume).
123-
- **Speaker/Headphone Volume:** Check the physical volume control and mute status on your speaker or headphones.
124-
- **Output Path:** Remember that **HDMI audio** and **Bluetooth® speakers** are not supported; use a **USB** audio device.
149+
If the interface works but there is no sound:
150+
- **Power Button:** Ensure the **POWER** switch in the web UI is **ON**.
151+
- **Pointer Position:** Ensure you are interacting with the upper part of the play area (bottom is zero volume).
152+
- **Volume Controls:** Increase the volume using the **+** button in the UI.
153+
- **Hardware Volume:** Check the physical volume control on your speaker.
154+
- **Audio Device:** Remember that **HDMI audio** and **Bluetooth® speakers** are not supported.
125155

126156
### Choppy or Crackling Audio
127-
128-
- **CPU Load:** Close any other applications running on the Arduino UNO Q that may be consuming significant resources.
129-
- **Power Supply:** Ensure you are using a stable, adequate power supply (5 V, 3 A) for the USB-C® hub, as insufficient power can affect USB peripheral performance.
157+
- **CPU Load:** Close other applications running on the Arduino UNO Q.
158+
- **Power Supply:** Ensure you are using a stable 5 V, 3 A power supply for the USB-C® hub. Insufficient power often degrades USB audio performance.
130159

131160
## Technical Details
132161

133162
- **Sample rate:** 16,000 Hz
134163
- **Audio format:** 32-bit float, little-endian
135-
- **Block duration:** ~30 ms
164+
- **Latency:** ~30 ms block duration
136165
- **Frequency range:** ~20 Hz to ~8,000 Hz
137-
- **Envelope:**
138-
- **Attack:** 0.01s (fast onset)
139-
- **Release:** 0.03s (quick fade out)
140-
- **Glide:** 0.02s (smooth pitch sliding)
141-
142-
## Compatibility Notes
143-
144-
- **Works with:**
145-
- **USB speakers** (cabled)
146-
- **USB wireless speaker receivers** (2.4 GHz dongles)
147-
- **Untested (may work):**
148-
- **USB‑C → 3.5 mm audio dongles** feeding analog speakers/headphones
149-
- **Not supported:**
150-
- **HDMI audio** output
151-
- **Bluetooth® speakers**
166+
- **Envelope:** Attack (0.01s), Release (0.03s), Glide (0.02s)

0 commit comments

Comments
 (0)