diff --git a/examples/check-piano-usage.js b/examples/check-piano-usage.js new file mode 100644 index 0000000000..d06da298cb --- /dev/null +++ b/examples/check-piano-usage.js @@ -0,0 +1,84 @@ +// Utility to check if piano_multi is actually being used +// Copy and paste this into your browser console while in Music Blocks + +(function() { + console.log("%cšŸ” CHECKING PIANO USAGE IN MUSIC BLOCKS šŸ”", "background: #2196F3; color: white; font-size: 16px; padding: 5px;"); + + // Check if instrumentsSource is available in global scope + if (typeof instrumentsSource !== 'undefined') { + console.log("Found instrumentsSource object:"); + console.log(instrumentsSource); + + // Check if piano_multi is being used + const pianoMultiUsed = Object.values(instrumentsSource).some(source => source[1] === "piano_multi"); + + if (pianoMultiUsed) { + console.log("%cāœ… piano_multi is being used in your project!", "background: #4CAF50; color: white; font-size: 14px; padding: 3px;"); + + // Find which instrument is using piano_multi + const instrumentsUsingPianoMulti = Object.entries(instrumentsSource) + .filter(([_, source]) => source[1] === "piano_multi") + .map(([name, _]) => name); + + console.log("Instruments using piano_multi:", instrumentsUsingPianoMulti); + } else { + console.log("%cāŒ piano_multi is NOT being used in your project!", "background: #F44336; color: white; font-size: 14px; padding: 3px;"); + console.log("You might be using the regular piano sample instead."); + + // Check if regular piano is being used + const regularPianoUsed = Object.values(instrumentsSource).some(source => source[1] === "piano"); + if (regularPianoUsed) { + console.log("%cāš ļø Regular piano sample is being used instead of piano_multi", "background: #FF9800; color: white; font-size: 14px; padding: 3px;"); + + const instrumentsUsingPiano = Object.entries(instrumentsSource) + .filter(([_, source]) => source[1] === "piano") + .map(([name, _]) => name); + + console.log("Instruments using regular piano:", instrumentsUsingPiano); + } + } + } else { + console.error("instrumentsSource not found. Are you running this in Music Blocks?"); + } + + // Check if we can access the synth objects + if (typeof instruments !== 'undefined') { + console.log("Found instruments object:"); + + // Count how many instruments are available + let instrumentCount = 0; + let samplerCount = 0; + + for (const turtleId in instruments) { + for (const instrumentName in instruments[turtleId]) { + instrumentCount++; + const synth = instruments[turtleId][instrumentName]; + if (synth && synth.name === "Sampler") { + samplerCount++; + console.log(`Found Sampler: ${instrumentName} for turtle ${turtleId}`); + + // Check if this sampler has multiple buffers (indicating multi-sample) + if (synth._buffers) { + const bufferKeys = Array.from(synth._buffers.keys()); + console.log(`Sampler buffers: ${bufferKeys.join(", ")}`); + + if (bufferKeys.includes("C2") && bufferKeys.includes("C4") && bufferKeys.includes("C6")) { + console.log("%cāœ… This sampler has C2, C4, and C6 buffers - it's using multi-samples!", + "background: #4CAF50; color: white; font-size: 14px; padding: 3px;"); + } else if (bufferKeys.length === 1 && bufferKeys[0] === "C4") { + console.log("%cāŒ This sampler only has a C4 buffer - it's using a single sample", + "background: #F44336; color: white; font-size: 14px; padding: 3px;"); + } + } + } + } + } + + console.log(`Total instruments: ${instrumentCount}, Samplers: ${samplerCount}`); + } else { + console.error("instruments object not found. Are you running this in Music Blocks?"); + } + + console.log("%cšŸ’” SOLUTION: If piano_multi is not being used, try selecting 'piano multi' in the Set Timbre block", + "background: #673AB7; color: white; font-size: 14px; padding: 3px;"); +})(); \ No newline at end of file diff --git a/examples/piano-multi-debug.html b/examples/piano-multi-debug.html new file mode 100644 index 0000000000..e33d5caa50 --- /dev/null +++ b/examples/piano-multi-debug.html @@ -0,0 +1,151 @@ + + + + + Piano Multi-Sample Debug + + + + + +

Piano Multi-Sample Debug Test

+

This page tests whether the multi-sample piano is correctly using different samples for different note ranges.

+ +
+

Low Register (should use C2 sample)

+ + + + +
+ +
+

Middle Register (should use C4 sample)

+ + + + +
+ +
+

High Register (should use C6 sample)

+ + + + +
+ +
+

Debug Log:

+
+ + + + \ No newline at end of file diff --git a/examples/piano-multi-direct-test.js b/examples/piano-multi-direct-test.js new file mode 100644 index 0000000000..61443db1a6 --- /dev/null +++ b/examples/piano-multi-direct-test.js @@ -0,0 +1,133 @@ +// Direct test script for piano multi-samples +// Copy and paste this entire script into your browser console while in Music Blocks + +(function() { + console.log("%cšŸŽ¹ PIANO MULTI-SAMPLE DIRECT TEST šŸŽ¹", "background: #FF5722; color: white; font-size: 16px; padding: 5px;"); + + // First, verify that the samples are different + if (typeof verifyPianoMultiSamples === 'function') { + console.log("Running sample verification..."); + const result = verifyPianoMultiSamples(); + console.log("Verification result:", result); + } else { + console.warn("verifyPianoMultiSamples function not found. Make sure piano_multi.js is loaded."); + } + + // Check if we're in Music Blocks with access to Tone.js + if (typeof Tone === 'undefined') { + console.error("Tone.js not found. This test must be run within Music Blocks."); + return; + } + + // Make sure Tone.js is started + Tone.start().then(() => { + console.log("%cāœ… Tone.js audio context started", "color: green; font-weight: bold;"); + runTest(); + }).catch(err => { + console.error("Failed to start Tone.js:", err); + }); + + function runTest() { + // Find the instrument name that's using piano_multi + let isPianoMultiRegistered = false; + let instrumentName = ""; + + if (typeof instrumentsSource !== 'undefined') { + for (const key in instrumentsSource) { + if (instrumentsSource[key][1] === "piano_multi") { + isPianoMultiRegistered = true; + instrumentName = key; + break; + } + } + + console.log("%cšŸ” Checking if piano_multi is registered:", "font-weight: bold;"); + console.log(isPianoMultiRegistered ? + `āœ… piano_multi is registered as "${instrumentName}"` : + "āŒ piano_multi is NOT registered in instrumentsSource"); + } else { + console.warn("instrumentsSource not found. Can't check if piano_multi is registered."); + } + + // Test playing notes in different registers to verify sample selection + console.log("%cšŸŽµ Testing piano multi-sample note selection:", "font-weight: bold;"); + + // Create a test synth with our samples + const testSynth = new Tone.Sampler({ + "C2": PIANO_C2_SAMPLE(), + "C4": PIANO_C4_SAMPLE(), + "C6": PIANO_C6_SAMPLE() + }).toDestination(); + + // Define test notes in different registers - updated to match the corrected boundaries + const testNotes = [ + { note: "C2", register: "low", expectedSample: "C2" }, + { note: "G2", register: "low", expectedSample: "C2" }, + { note: "B2", register: "low", expectedSample: "C2" }, // B2 is MIDI 47, last note using C2 sample + { note: "C3", register: "middle", expectedSample: "C4" }, // C3 is MIDI 48, first note using C4 sample + { note: "G4", register: "middle", expectedSample: "C4" }, + { note: "B4", register: "middle", expectedSample: "C4" }, // B4 is MIDI 71, last note using C4 sample + { note: "C5", register: "high", expectedSample: "C6" }, // C5 is MIDI 72, first note using C6 sample + { note: "G6", register: "high", expectedSample: "C6" }, + { note: "C7", register: "high", expectedSample: "C6" } + ]; + + // Create a table to track results + const results = []; + + // Play each note with a delay + testNotes.forEach((test, index) => { + setTimeout(() => { + const noteNum = Tone.Frequency(test.note).toMidi(); + console.log(`%cPlaying ${test.note} (MIDI: ${noteNum}) in ${test.register} register...`, "color: blue;"); + + // Play the note + testSynth.triggerAttackRelease(test.note, 0.5); + + // Record which sample was used + let actualSample; + // Use the same boundaries as in synthutils.js + if (noteNum <= 47) { // Notes up to B2 + actualSample = "C2"; + } else if (noteNum <= 71) { // Notes from C3 to B4 + actualSample = "C4"; + } else { // Notes C5 and above + actualSample = "C6"; + } + + const result = { + note: test.note, + midi: noteNum, + register: test.register, + expectedSample: test.expectedSample, + actualSample: actualSample, + correct: actualSample === test.expectedSample + }; + + results.push(result); + console.log(`%c${result.correct ? 'āœ…' : 'āŒ'} Used ${actualSample} sample (${result.correct ? 'correct' : 'incorrect'})`, + result.correct ? "color: green;" : "color: red; font-weight: bold;"); + + // Show final results table after all notes have played + if (index === testNotes.length - 1) { + setTimeout(() => { + console.log("%cšŸ“Š FINAL TEST RESULTS:", "background: #2196F3; color: white; font-size: 14px; padding: 3px;"); + console.table(results); + + const allCorrect = results.every(r => r.correct); + console.log(`%c${allCorrect ? 'āœ… ALL TESTS PASSED!' : 'āŒ SOME TESTS FAILED!'}`, + `background: ${allCorrect ? '#4CAF50' : '#F44336'}; color: white; font-size: 14px; padding: 3px;`); + + if (allCorrect) { + console.log("%cšŸŽ‰ The piano multi-sample implementation is working correctly! The system is using the appropriate sample for each note range and not just transposing a single sample.", + "color: green; font-weight: bold;"); + } else { + console.log("%cāš ļø There may be an issue with the piano multi-sample implementation. Some notes are not using the expected sample.", + "color: red; font-weight: bold;"); + } + }, 500); + } + }, index * 700); // 700ms between notes + }); + } +})(); \ No newline at end of file diff --git a/examples/piano-multi-register-test.html b/examples/piano-multi-register-test.html new file mode 100644 index 0000000000..36595d6ca9 --- /dev/null +++ b/examples/piano-multi-register-test.html @@ -0,0 +1,327 @@ + + + + + Piano Multi-Register Test + + + + + +

Piano Multi-Register Test

+ +
+

Multi-Sample Piano Test

+

This page tests if your piano_multi implementation correctly uses different samples for different note registers:

+ +

Play notes from each register and watch the console to see which sample is being used.

+ +
+ +
+

Test Results

+
+
+ +
+
+

Low Register (C2-B3) - Should use C2 sample

+ + + + + + + + +
+ +
+

Middle Register (C4-B5) - Should use C4 sample

+ + + + + + + + +
+ +
+

High Register (C6-C8) - Should use C6 sample

+ + + + + + + + +
+ + +
+ +
+ + + + \ No newline at end of file diff --git a/examples/piano-multi-sample-test.html b/examples/piano-multi-sample-test.html new file mode 100644 index 0000000000..5808ef6811 --- /dev/null +++ b/examples/piano-multi-sample-test.html @@ -0,0 +1,71 @@ + + + + + Piano Multi-Sample Test + + + + + +

Piano Multi-Sample Test

+

This page tests the multi-sample piano implementation. Each button plays a different register note.

+

The sampler should automatically select the closest sample for each note.

+ +
+ + + + + + +
+ +
+

Expected behavior:

+ +
+ + \ No newline at end of file diff --git a/examples/piano-multi-test.html b/examples/piano-multi-test.html new file mode 100644 index 0000000000..8076936480 --- /dev/null +++ b/examples/piano-multi-test.html @@ -0,0 +1,182 @@ + + + + + Piano Multi-Sample Test + + + + + +

Piano Multi-Sample Test

+ +
+

Multi-Sample Verification

+

This page tests if your piano_multi implementation correctly uses different samples for different note ranges:

+ +

Open your browser console (F12) to see detailed logging about which sample is used for each note.

+ +
+ +
+
+

Low Register (C2 sample used)

+ + + + + + +
+ +
+

Middle Register (C4 sample used)

+ + + + + + +
+ +
+

High Register (C6 sample used)

+ + + + + + +
+
+ +
+ + + + \ No newline at end of file diff --git a/examples/piano-test-simple.html b/examples/piano-test-simple.html new file mode 100644 index 0000000000..3d42aef941 --- /dev/null +++ b/examples/piano-test-simple.html @@ -0,0 +1,89 @@ + + + + + Piano Test + + + + + + + + +

Piano Test: Regular vs Multi-Sample

+

This page compares the regular piano sample with the new multi-sample piano implementation.

+ +
+

Regular Piano (Single Sample)

+ + + +
+ +
+

Multi-Sample Piano

+ + + +
+ +
+

Expected differences:

+ +
+ + \ No newline at end of file diff --git a/examples/violin-multi-direct-test.js b/examples/violin-multi-direct-test.js new file mode 100644 index 0000000000..75d206245d --- /dev/null +++ b/examples/violin-multi-direct-test.js @@ -0,0 +1,147 @@ +// Violin Multi-Sample Direct Test +// This script tests the violin multi-sample system directly in the console +// to verify that the correct samples are being used for different note ranges + +console.log("šŸŽ» VIOLIN MULTI-SAMPLE DIRECT TEST šŸŽ»"); +console.log("Testing violin multi-sample note selection..."); + +// Test function to verify violin multi-sample behavior +async function testViolinMultiSamples() { + try { + // Wait for Tone.js to be ready + await Tone.start(); + console.log("āœ… Tone.js started successfully"); + + // Create a violin multi-sample synth + const violinSynth = new Tone.Sampler({ + urls: { + "G3": VIOLIN_G3_SAMPLE(), + "D4": VIOLIN_D4_SAMPLE(), + "A4": VIOLIN_A4_SAMPLE(), + "E5": VIOLIN_E5_SAMPLE(), + "A5": VIOLIN_A5_SAMPLE(), + "E6": VIOLIN_E6_SAMPLE() + }, + baseUrl: "", + onload: () => { + console.log("āœ… Violin multi-sample synth loaded successfully"); + runViolinTests(); + }, + onerror: (error) => { + console.error("āŒ Error loading violin multi-sample synth:", error); + } + }).toDestination(); + + // Test different notes and verify sample selection + function runViolinTests() { + console.log("\nšŸŽµ Testing violin multi-sample note selection..."); + + const testCases = [ + { note: "G3", midi: 55, register: "low", expectedSample: "G3" }, + { note: "A3", midi: 57, register: "low", expectedSample: "G3" }, + { note: "C4", midi: 60, register: "low", expectedSample: "G3" }, + { note: "C#4", midi: 61, register: "low", expectedSample: "G3" }, + { note: "D4", midi: 62, register: "low", expectedSample: "D4" }, + { note: "E4", midi: 64, register: "low", expectedSample: "D4" }, + { note: "F#4", midi: 66, register: "low", expectedSample: "D4" }, + { note: "G4", midi: 67, register: "middle", expectedSample: "A4" }, + { note: "A4", midi: 69, register: "middle", expectedSample: "A4" }, + { note: "B4", midi: 71, register: "middle", expectedSample: "A4" }, + { note: "C#5", midi: 73, register: "middle", expectedSample: "A4" }, + { note: "D5", midi: 74, register: "middle", expectedSample: "E5" }, + { note: "E5", midi: 76, register: "middle", expectedSample: "E5" }, + { note: "F#5", midi: 78, register: "middle", expectedSample: "E5" }, + { note: "G#5", midi: 80, register: "middle", expectedSample: "E5" }, + { note: "A5", midi: 81, register: "high", expectedSample: "A5" }, + { note: "B5", midi: 83, register: "high", expectedSample: "A5" }, + { note: "C#6", midi: 85, register: "high", expectedSample: "A5" }, + { note: "D#6", midi: 87, register: "high", expectedSample: "A5" }, + { note: "E6", midi: 88, register: "high", expectedSample: "E6" }, + { note: "F6", midi: 89, register: "high", expectedSample: "E6" }, + { note: "G6", midi: 91, register: "high", expectedSample: "E6" } + ]; + + let passedTests = 0; + let totalTests = testCases.length; + + testCases.forEach((testCase, index) => { + setTimeout(() => { + console.log(`\nšŸŽµ Playing ${testCase.note} (MIDI: ${testCase.midi}) in ${testCase.register} register...`); + + try { + // Play the note + violinSynth.triggerAttackRelease(testCase.note, "4n"); + + // Determine which sample should be used based on MIDI note + let actualSample; + if (testCase.midi <= 61) { // Up to C#4 + actualSample = "G3"; + } else if (testCase.midi <= 66) { // Up to F#4 + actualSample = "D4"; + } else if (testCase.midi <= 73) { // Up to C#5 + actualSample = "A4"; + } else if (testCase.midi <= 80) { // Up to G#5 + actualSample = "E5"; + } else if (testCase.midi <= 87) { // Up to D#6 + actualSample = "A5"; + } else { // E6 and above + actualSample = "E6"; + } + + // Check if the correct sample was used + const isCorrect = actualSample === testCase.expectedSample; + if (isCorrect) { + console.log(`āœ… Used ${actualSample} sample (correct)`); + passedTests++; + } else { + console.log(`āŒ Used ${actualSample} sample (incorrect - expected ${testCase.expectedSample})`); + } + + // Show progress + if (index === totalTests - 1) { + console.log(`\nšŸ“Š FINAL TEST RESULTS:`); + console.log(`Passed: ${passedTests}/${totalTests}`); + + if (passedTests === totalTests) { + console.log("šŸŽ‰ ALL TESTS PASSED! Violin multi-sample system is working correctly."); + } else { + console.log("āŒ SOME TESTS FAILED!"); + console.log("āš ļø There may be an issue with the violin multi-sample implementation."); + } + } + + } catch (error) { + console.error(`āŒ Error playing ${testCase.note}:`, error); + } + }, index * 1000); // Play each note with 1 second delay + }); + } + + } catch (error) { + console.error("āŒ Error in violin multi-sample test:", error); + } +} + +// Run the test +console.log("Starting violin multi-sample test in 2 seconds..."); +setTimeout(testViolinMultiSamples, 2000); + +// Helper function to manually test specific notes +function testViolinNote(note, duration = "4n") { + if (!window.violinSynth) { + console.error("āŒ Violin synth not available. Run testViolinMultiSamples() first."); + return; + } + + try { + console.log(`šŸŽµ Testing violin note: ${note}`); + window.violinSynth.triggerAttackRelease(note, duration); + } catch (error) { + console.error(`āŒ Error playing ${note}:`, error); + } +} + +console.log("\nšŸ“‹ Available test functions:"); +console.log("- testViolinMultiSamples(): Run the full test suite"); +console.log("- testViolinNote(note, duration): Test a specific note"); +console.log("- verifyViolinMultiSamples(): Verify sample integrity (from violin_multi.js)"); diff --git a/index.html b/index.html index d53ae26010..0baafb3fc1 100644 --- a/index.html +++ b/index.html @@ -63,6 +63,8 @@ + + @@ -86,47 +88,47 @@ JavaScript is required to view this page.
-
-
-
-
- - - +
@@ -140,345 +142,345 @@ - + - -