Skip to content

Commit b99e4a7

Browse files
committed
test(core): deterministic detune integration test; docs: check off microtonality tasks in TODO
1 parent d5a9b12 commit b99e4a7

File tree

2 files changed

+37
-60
lines changed

2 files changed

+37
-60
lines changed

docs/TODO.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ This document outlines the path from the current **A-** grade to **S-tier** stat
1212
- [x] Property-based testing for mathematical functions
1313
- [x] Improved WebGPU error handling with user feedback
1414
- [x] Comprehensive shader documentation
15-
- [x] 25 total tests passing with zero warnings
15+
- [x] 31 tests passing with zero warnings
1616

1717
---
1818

@@ -22,11 +22,11 @@ This document outlines the path from the current **A-** grade to **S-tier** stat
2222

2323
#### 1.1 Foundation
2424

25-
- [ ] **Add microtonal detune support**
26-
- [ ] Add `detune_cents: f32` to `EngineParams` (default 0.0, range ±200¢)
27-
- [ ] Update `midi_to_hz()` to accept fractional MIDI values for cent precision
28-
- [ ] Unit tests: verify 50¢ detune accuracy, round-trip expectations, extreme values
29-
- [ ] Integration test: ensure detune affects all generated notes consistently
25+
- [x] **Add microtonal detune support**
26+
- [x] Add `detune_cents: f32` to `EngineParams` (default 0.0, range ±200¢)
27+
- [x] Update `midi_to_hz()` to accept fractional MIDI values for cent precision
28+
- [x] Unit tests: verify 50¢ detune accuracy, round-trip expectations, extreme values
29+
- [x] Integration test: ensure detune affects all generated notes consistently
3030

3131
#### 1.2 Alternative Tuning Systems
3232

@@ -42,11 +42,11 @@ This document outlines the path from the current **A-** grade to **S-tier** stat
4242

4343
#### 1.3 User Interface
4444

45-
- [ ] **Keyboard controls for microtonality**
46-
- [ ] `,` key: decrease global detune by 50¢ (Shift+`,` for 10¢ fine adjustment)
47-
- [ ] `.` key: increase global detune by 50¢ (Shift+`.` for 10¢ fine adjustment)
48-
- [ ] `/` key: reset detune to 0¢
49-
- [ ] Update hint overlay: "Detune: +50¢" or "Scale: 24-TET pentatonic"
45+
- [x] **Keyboard controls for microtonality**
46+
- [x] `,` key: decrease global detune by 50¢ (Shift+`,` for 10¢ fine adjustment)
47+
- [x] `.` key: increase global detune by 50¢ (Shift+`.` for 10¢ fine adjustment)
48+
- [x] `/` key: reset detune to 0¢
49+
- [x] Update hint overlay: shows "Detune: ±N¢" and BPM/Scale
5050
- [ ] **Scale selection shortcuts**
5151
- [ ] `8` key → 19-TET pentatonic
5252
- [ ] `9` key → 24-TET pentatonic

tests/music_tests.rs

Lines changed: 26 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -271,63 +271,40 @@ fn engine_detune_methods() {
271271

272272
#[test]
273273
fn engine_schedule_with_detune() {
274-
let mut engine = make_engine();
275-
println!("Initial engine detune: {}¢", engine.params.detune_cents);
276-
277-
engine.set_detune_cents(50.0); // +50¢ detune
278-
println!(
279-
"After set_detune_cents(50.0): {}¢",
280-
engine.params.detune_cents
281-
);
274+
// Deterministic: 1 voice, prob=1.0, scale=[0], root=C4
275+
let configs = vec![VoiceConfig {
276+
waveform: Waveform::Sine,
277+
base_position: glam::Vec3::new(0.0, 0.0, 0.0),
278+
trigger_probability: 1.0,
279+
octave_offset: 0,
280+
base_duration: 0.25,
281+
}];
282+
let params = EngineParams {
283+
scale: &[0],
284+
root_midi: 60,
285+
..EngineParams::default()
286+
};
287+
let mut engine = MusicEngine::new(configs, params, 12345);
282288

283-
// Test the detune function directly
284-
let test_midi = 48.0;
285-
let test_detune = 50.0;
286-
let direct_result = midi_to_hz_with_detune(test_midi, test_detune);
287-
let expected_result = midi_to_hz(test_midi + test_detune / 100.0);
288-
println!(
289-
"Direct test: MIDI {test_midi:.1} + {test_detune}¢ = {direct_result:.6} Hz (expected: {expected_result:.6})"
290-
);
291-
292-
// Let's test a single event generation to isolate the issue
289+
engine.set_detune_cents(50.0);
293290
let mut events = Vec::new();
294291
let seconds_per_beat = 60.0 / engine.params.bpm as f64;
295-
296-
// Generate just one event
297292
engine.tick(Duration::from_secs_f64(seconds_per_beat / 2.0), &mut events);
298293

299-
println!("Generated {} events", events.len());
300-
301-
if let Some(event) = events.first() {
302-
let voice_config = &engine.configs[event.voice_index];
303-
let degree = engine.params.scale[0];
304-
let octave = voice_config.octave_offset;
305-
let midi = engine.params.root_midi + degree + octave * 12;
306-
let expected_freq = midi_to_hz(midi as f32);
307-
let expected_detuned = midi_to_hz_with_detune(midi as f32, engine.params.detune_cents);
308-
309-
let voice_index = event.voice_index;
310-
let base_freq = expected_freq;
311-
let detuned_freq = event.frequency_hz;
294+
assert!(
295+
!events.is_empty(),
296+
"expected at least one event with probability=1.0"
297+
);
312298

313-
println!(
314-
"Single event: voice={voice_index}, degree={degree}, octave={octave}, midi={midi}, base_freq={base_freq:.6}, detuned_freq={detuned_freq:.6}, expected_detuned={expected_detuned:.6}"
299+
let expected = midi_to_hz_with_detune(60.0, engine.params.detune_cents);
300+
for ev in &events {
301+
assert!(
302+
(ev.frequency_hz - expected).abs() < 1e-6,
303+
"scheduled freq does not include detune: got {:.6}, expected {:.6}",
304+
ev.frequency_hz,
305+
expected
315306
);
316-
317-
// Check if the event frequency matches what we expect
318-
if (event.frequency_hz - expected_detuned).abs() > 1e-6 {
319-
println!(" MISMATCH: Event frequency doesn't match expected detuned frequency!");
320-
println!(" This suggests the engine is not using midi_to_hz_with_detune correctly");
321-
} else {
322-
println!(" SUCCESS: Event frequency matches expected detuned frequency");
323-
}
324307
}
325-
326-
// For now, let's just verify that the engine detune setting is correct
327-
assert_eq!(
328-
engine.params.detune_cents, 50.0,
329-
"Engine detune should be 50¢"
330-
);
331308
}
332309

333310
#[test]

0 commit comments

Comments
 (0)