|
|
@ -1,11 +1,46 @@ |
|
|
|
import * as Tone from "tone"; |
|
|
|
import { pushToSonificationLog } from "../log/SensorLogger"; |
|
|
|
import drumSample from "./samples/snare_drum.wav"; |
|
|
|
import C2Flute from "./samples/flute_samples/C2.wav"; |
|
|
|
import C3Flute from "./samples/flute_samples/C3.wav"; |
|
|
|
import C4Flute from "./samples/flute_samples/C4.wav"; |
|
|
|
import A2Flute from "./samples/flute_samples/A2.wav"; |
|
|
|
import ASharp3Flute from "./samples/flute_samples/A#3.wav"; |
|
|
|
import ASharp4Flute from "./samples/flute_samples/A#4.wav"; |
|
|
|
import D2Flute from "./samples/flute_samples/D2.wav"; |
|
|
|
import D3Flute from "./samples/flute_samples/D3.wav"; |
|
|
|
import D4Flute from "./samples/flute_samples/D4.wav"; |
|
|
|
import FSharp2Flute from "./samples/flute_samples/F#2.wav"; |
|
|
|
import FSharp3Flute from "./samples/flute_samples/F#3.wav"; |
|
|
|
import FSharp4Flute from "./samples/flute_samples/F#4.wav"; |
|
|
|
import violaSample from "./samples/viola.wav"; |
|
|
|
|
|
|
|
import { getMotifByVersion } from "./MotifHandler"; |
|
|
|
import { generateChord } from "./ChordHelper"; |
|
|
|
|
|
|
|
const drumSynth = new Tone.Sampler({ |
|
|
|
C3: drumSample, |
|
|
|
}).toDestination(); |
|
|
|
|
|
|
|
const violaSynth = new Tone.Sampler({ |
|
|
|
C5: violaSample, |
|
|
|
}).toDestination(); |
|
|
|
|
|
|
|
const fluteSynth = new Tone.Sampler({ |
|
|
|
C2: C2Flute, |
|
|
|
C3: C3Flute, |
|
|
|
C4: C4Flute, |
|
|
|
A2: A2Flute, |
|
|
|
"A#3": ASharp3Flute, |
|
|
|
"A#4": ASharp4Flute, |
|
|
|
D2: D2Flute, |
|
|
|
D3: D3Flute, |
|
|
|
D4: D4Flute, |
|
|
|
"F#2": FSharp2Flute, |
|
|
|
"F#3": FSharp3Flute, |
|
|
|
"F#4": FSharp4Flute, |
|
|
|
}).toDestination(); |
|
|
|
|
|
|
|
const setRotation = (angle) => { |
|
|
|
Tone.Listener.forwardX.value = Math.sin(angle); |
|
|
|
Tone.Listener.forwardY.value = 0; |
|
|
@ -18,6 +53,22 @@ const setRotationRamp = (panner, angle, rampTime) => { |
|
|
|
panner.positionZ.rampTo(-Math.cos(angle), rampTime); |
|
|
|
}; |
|
|
|
|
|
|
|
// First three are small, then medium, then large and the link chooses the corresponding motif within the category... |
|
|
|
const calculateDetailMotifVersion = function (textDensity, linkDensity) { |
|
|
|
return 3 * textDensity + linkDensity; |
|
|
|
}; |
|
|
|
|
|
|
|
const tabChordProgression = [ |
|
|
|
generateChord(60, "major"), |
|
|
|
generateChord(62, "minor"), |
|
|
|
generateChord(64, "minor"), |
|
|
|
generateChord(65, "major"), |
|
|
|
generateChord(67, "major"), |
|
|
|
generateChord(69, "minor"), |
|
|
|
generateChord(71, "diminished"), |
|
|
|
generateChord(72, "major"), |
|
|
|
]; |
|
|
|
|
|
|
|
var offCooldown = true; |
|
|
|
|
|
|
|
const playChordEndSound = function () { |
|
|
@ -42,14 +93,30 @@ const playChordEndSound = function () { |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
const calculatePlayedTabChord = function (endReached, tabIndex, tabAmount) { |
|
|
|
const progress = tabIndex / (tabAmount - 1); |
|
|
|
const chordListLength = tabChordProgression.length; |
|
|
|
|
|
|
|
if (!endReached) { |
|
|
|
return Math.floor(progress * (chordListLength - 1)); |
|
|
|
} |
|
|
|
return Math.floor((1 - progress) * (chordListLength - 1)) + 1; |
|
|
|
}; |
|
|
|
|
|
|
|
// Maybe also dat... |
|
|
|
export function playTabEarconSonification() { |
|
|
|
export function playTabEarconSonification(endReached, tabIndex, tabAmount) { |
|
|
|
if (offCooldown) { |
|
|
|
var loop = new Tone.Loop((time) => { |
|
|
|
drumSynth.triggerAttackRelease("C3", "4n", time); |
|
|
|
}, "4n"); |
|
|
|
loop.iterations = 2; |
|
|
|
loop.start(); |
|
|
|
const now = Tone.now(); |
|
|
|
const tabChordIndex = calculatePlayedTabChord( |
|
|
|
endReached, |
|
|
|
tabIndex, |
|
|
|
tabAmount |
|
|
|
); |
|
|
|
fluteSynth.triggerAttackRelease( |
|
|
|
tabChordProgression[tabChordIndex], |
|
|
|
"4n", |
|
|
|
now |
|
|
|
); |
|
|
|
Tone.Transport.start(); |
|
|
|
pushToSonificationLog("tab_earcon"); |
|
|
|
offCooldown = false; |
|
|
@ -60,8 +127,7 @@ export function playTabEarconSonification() { |
|
|
|
} |
|
|
|
|
|
|
|
export function playTabModelSonification(pannerVal, frequencyVal, endReached) { |
|
|
|
|
|
|
|
if(endReached) { |
|
|
|
if (endReached) { |
|
|
|
playChordEndSound(); |
|
|
|
return; |
|
|
|
} |
|
|
@ -97,12 +163,11 @@ export function playTabModelSonification(pannerVal, frequencyVal, endReached) { |
|
|
|
// Menu Sonification Paper. :) |
|
|
|
export function playDetailEarconSonification(textDensity, linkDensity) { |
|
|
|
if (offCooldown) { |
|
|
|
var loop = new Tone.Loop((time) => { |
|
|
|
drumSynth.triggerAttackRelease("C3", "4n", time); |
|
|
|
}, "4n"); |
|
|
|
loop.iterations = 2; |
|
|
|
loop.start(); |
|
|
|
drumSynth.context.resume(); |
|
|
|
const synth = violaSynth.toDestination(); |
|
|
|
getMotifByVersion( |
|
|
|
calculateDetailMotifVersion(textDensity, linkDensity), |
|
|
|
synth |
|
|
|
); |
|
|
|
Tone.Transport.start(); |
|
|
|
pushToSonificationLog("detail_earcon"); |
|
|
|
offCooldown = false; |
|
|
|