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:
+
+
Low Register (C2-B3): Uses the C2 sample
+
Middle Register (C4-B5): Uses the C4 sample
+
High Register (C6-C8): Uses the C6 sample
+
+
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:
+
+
C2 and C3 should use the C2 sample (transposed for C3)
+
C4 and C5 should use the C4 sample (transposed for C5)
+
C6 and C7 should use the C6 sample (transposed for C7)
+
+
+
+
\ 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:
+
+
C2 sample for notes C2-B3 (low register)
+
C4 sample for notes C4-B5 (middle register)
+
C6 sample for notes C6-C8 (high register)
+
+
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:
+
+
The regular piano uses a single sample (C4) transposed for all notes
+
The multi-sample piano uses different samples for different registers:
+
+
C2 for low register
+
C4 for middle register
+
C6 for high register
+
+
+
The multi-sample piano should sound more natural, especially at the extremes
+
+
+
+
\ 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.
-