From 74520503f9d175f8ce94eced163f9256065ae1d8 Mon Sep 17 00:00:00 2001 From: danigb Date: Thu, 11 Apr 2024 18:02:06 +0200 Subject: [PATCH] fix: detune start param (#74) * feat: add detuneto piano keyboard * fix: findSampleInRegion includes user's detune param * chore: bump version * fix: changelog --- CHANGELOG.md | 22 ++++++++-------------- package.json | 2 +- site/src/PianoKeyboard.tsx | 15 +++++++++++++-- src/player/layers.test.ts | 17 +++++++++++++++++ src/player/layers.ts | 3 ++- 5 files changed, 41 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a14fd8c..426b7a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,21 +13,14 @@ const context = new AudioContext(); const drums = new DrumMachine(context, { instrument: { baseUrl: "https://smpldsnds.github.io/drum-machines/roland-cr-8000/", - name: "roland-cr-8000", + name: "Roland-CR-8000", samples: [ - "Cr8kbass", - "Cr8kchat", - "Cr8kclap", - "Cr8kclav", - "Cr8kcowb", - "Cr8kcymb", - "Cr8khitm", - "Cr8klcng", - "Cr8klotm", - "Cr8kmcng", - "Cr8kohat", - "Cr8krim", - "Cr8ksnar", + "hihat-closed", + "hihat-open", + "kick", + "snare", + "tom-high", + "tom-low", ], formats: ["ogg", "m4a"], }, @@ -35,6 +28,7 @@ const drums = new DrumMachine(context, { ``` - DrumMachine uses https://github.com/smpldsnds/drum-machines as source of samples +- Fix: `detune` param on `start` method ## 0.12.x diff --git a/package.json b/package.json index ff10f8a..a819eab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "smplr", - "version": "0.13.2", + "version": "0.13.3", "homepage": "https://github.com/danigb/smplr#readme", "description": "A Sampled collection of instruments", "main": "dist/index.js", diff --git a/site/src/PianoKeyboard.tsx b/site/src/PianoKeyboard.tsx index 413ae95..0afa36d 100644 --- a/site/src/PianoKeyboard.tsx +++ b/site/src/PianoKeyboard.tsx @@ -10,6 +10,7 @@ const isBlack = (midi: number) => [1, 3, 6, 8, 10].includes(midi % 12); type PianoKeyboardNote = { note: number; velocity: number; + detune: number; time?: number; duration?: number; }; @@ -26,6 +27,7 @@ export function PianoKeyboard({ onRelease?: (midi: number) => void; }) { const [velocity, setVelocity] = useState(100); + const [detune, setDetune] = useState(0); const [oct, setOct] = useState(60); const [sustain, setSustain] = useState(false); const isPlaying = (midi: number) => false; @@ -44,7 +46,7 @@ export function PianoKeyboard({ className={`accidental-key ${ isPlaying(midi) ? "accidental-key--playing" : "" }`} - onMouseDown={() => onPress({ note: midi, velocity })} + onMouseDown={() => onPress({ note: midi, velocity, detune })} onMouseUp={() => release(midi)} >
@@ -56,7 +58,7 @@ export function PianoKeyboard({ className={`natural-key ${ isPlaying(midi) ? "natural-key--playing" : "" }`} - onMouseDown={() => onPress({ note: midi, velocity })} + onMouseDown={() => onPress({ note: midi, velocity, detune })} onMouseUp={() => release(midi)} >
@@ -93,6 +95,14 @@ export function PianoKeyboard({ value={velocity} onChange={(e) => setVelocity(e.target.valueAsNumber)} /> +
Detune: {detune}
+ setDetune(e.target.valueAsNumber)} + /> { ]); }); + it("applies given detune", () => { + const group: RegionGroup = { + regions: [ + { sampleName: "a", midiPitch: 60, midiLow: 60, midiHigh: 75 }, + { sampleName: "b", midiPitch: 75, midiLow: 70, midiHigh: 80 }, + ], + sample: {}, + }; + + expect(findSamplesInRegions(group, { note: 60, detune: 50 })).toEqual([ + { name: "a", detune: 50, note: 60 }, + ]); + expect(findSamplesInRegions(group, { note: 62, detune: -50 })).toEqual([ + { name: "a", detune: 150, note: 62 }, + ]); + }); + it("finds finds with non integer midi", () => { const group: RegionGroup = { regions: [ diff --git a/src/player/layers.ts b/src/player/layers.ts index c7d6df1..78853c2 100644 --- a/src/player/layers.ts +++ b/src/player/layers.ts @@ -78,10 +78,11 @@ function findSampleInRegion( const velocity = sample.velocity ?? defaults.velocity; const regionGainOffset = region.volume ? dbToGain(region.volume) : 0; const sampleGainOffset = sample.gainOffset ?? defaults.gainOffset ?? 0; + const sampleDetune = sample.detune ?? 0; return { decayTime: sample?.decayTime ?? region.sample?.decayTime ?? defaults.decayTime, - detune: 100 * (semitones + (region.tune ?? 0)), + detune: 100 * (semitones + (region.tune ?? 0)) + sampleDetune, duration: sample?.duration ?? region.sample?.duration ?? defaults.duration, gainOffset: sampleGainOffset + regionGainOffset || undefined, loop: sample?.loop ?? region.sample?.loop ?? defaults.loop,