summaryrefslogtreecommitdiff
path: root/client/lib/sampler.js
blob: 59f8562b3668cd8ca62a12175bbe942b05451123 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/**
 * Sampler
 * @module lib/sampler.js;
 */

import Tone from "tone";

let root = 440;

let output;
let ready;
let current = "";
let samples = {};

const player_count = 12;

export function load(out, readyCallback) {
  output = out;
  ready = readyCallback;
  document.body.addEventListener("dragover", dragOver);
  document.body.addEventListener("drop", drop);
}

/**
 * Drag and drop
 */
export function dragOver(event) {
  event.preventDefault();
}
export function drop(event) {
  event.preventDefault();
  const files = event.dataTransfer.items
    ? [...event.dataTransfer.items]
        .filter((item) => item.kind === "file")
        .map((item) => item.getAsFile())
    : [...event.dataTransfer.files];

  const file = files[0];
  const reader = new FileReader();

  reader.addEventListener(
    "load",
    () => loadSampleFromFile(file, reader.result),
    false,
  );

  if (file) {
    reader.readAsDataURL(file);
  }
}

export function loadSampleFromFile(file, url) {
  const { name } = file;
  current = name;

  const sample = (samples[name] = samples[name] || {});
  sample.root = 440;
  sample.players = [];
  sample.index = -1;
  for (let i = 0; i < player_count; i++) {
    let player = new Tone.Player({
      url,
      retrigger: true,
      playbackRate: 1,
    });
    player.name = name;
    player.connect(output);
    sample.players.push(player);
  }
  console.log("+ Sampler:", name, `(${sample.players.length} voices)`);
  ready();
}

/**
 * Player
 */
let last = [1, 440];

function stop() {
  for (const sample of Object.values(samples)) {
    sample.players.forEach((player) => player.stop());
  }
}
function play(interval, root) {
  last = [interval, root];
  const sample = samples[current];
  sample.index = (sample.index + 1) % sample.players.length;
  const player = sample.players[sample.index];
  player.playbackRate = (interval * root) / sample.root;
  player.start();
}

function pause() {
  // no-op
}

export default { load, play, pause, stop };

// for help tuning
function keydown(e) {
  if (document.activeElement !== document.body) {
    return;
  }
  // console.log(e.keyCode)
  if (e.metaKey && last && current) {
    const sample = samples[current];
    const step = e.shiftKey ? (e.ctrlKey ? 0.1 : 1) : 10;
    switch (e.keyCode) {
      case 38: // up
        e.preventDefault();
        sample.root -= step;
        stop();
        play(last[0], last[1]);
        break;
      case 40: // down
        e.preventDefault();
        sample.root += step;
        stop();
        play(last[0], last[1]);
        break;
    }
  }
}
window.addEventListener("keydown", keydown, true);