File size: 7,450 Bytes
f8b493b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
function _array_like_to_array(arr, len) {
    if (len == null || len > arr.length) len = arr.length;
    for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
    return arr2;
}
function _array_with_holes(arr) {
    if (Array.isArray(arr)) return arr;
}
function _iterable_to_array_limit(arr, i) {
    var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
    if (_i == null) return;
    var _arr = [];
    var _n = true;
    var _d = false;
    var _s, _e;
    try {
        for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
            _arr.push(_s.value);
            if (i && _arr.length === i) break;
        }
    } catch (err) {
        _d = true;
        _e = err;
    } finally{
        try {
            if (!_n && _i["return"] != null) _i["return"]();
        } finally{
            if (_d) throw _e;
        }
    }
    return _arr;
}
function _non_iterable_rest() {
    throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _sliced_to_array(arr, i) {
    return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
}
function _unsupported_iterable_to_array(o, minLen) {
    if (!o) return;
    if (typeof o === "string") return _array_like_to_array(o, minLen);
    var n = Object.prototype.toString.call(o).slice(8, -1);
    if (n === "Object" && o.constructor) n = o.constructor.name;
    if (n === "Map" || n === "Set") return Array.from(n);
    if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
}
import * as Tone from 'https://esm.sh/tone';
// --- Module State ---
var players = null;
var isLoaded = false;
var sequence = null;
var beatIndex = 0;
var activeDrums = new Set();
// More varied and syncopated drum patterns
var drumPattern = {
    // Syncopated kick pattern
    //'kick':  [true, false, false, false, true, false, false, false, true, false, false, false, true, false, false, false],
    'kick': [
        true,
        false,
        false,
        false,
        false,
        true,
        false,
        false,
        true,
        false,
        false,
        true,
        false,
        true,
        false,
        false
    ],
    // Snare on the backbeat (beats 2 and 4)
    'snare': [
        false,
        false,
        false,
        false,
        true,
        false,
        false,
        false,
        false,
        false,
        false,
        false,
        true,
        false,
        false,
        false
    ],
    // Open hi-hat feel on the off-beats
    'hihat': [
        false,
        true,
        false,
        true,
        false,
        true,
        false,
        true,
        false,
        true,
        false,
        true,
        false,
        true,
        false,
        true
    ],
    // Clap layered with snare, but with an extra syncopated hit
    'clap': [
        false,
        false,
        false,
        false,
        true,
        false,
        false,
        true,
        false,
        false,
        false,
        false,
        true,
        false,
        false,
        false
    ]
};
var fingerToDrumMap = {
    'index': 'kick',
    'middle': 'snare',
    'ring': 'hihat',
    'pinky': 'clap'
};
// --- Exported Functions ---
/**
 * Loads all drum samples and returns a promise that resolves when loading is complete
 */ export function loadSamples() {
    return new Promise(function(resolve, reject) {
        if (isLoaded) {
            resolve();
            return;
        }
        players = new Tone.Players({
            urls: {
                kick: 'assets/kick.wav',
                snare: 'assets/snare.wav',
                hihat: 'assets/hihat.wav',
                clap: 'assets/clap.wav'
            },
            onload: function() {
                isLoaded = true;
                // Set volumes after loading
                players.player('kick').volume.value = -6; // Lowered kick volume
                players.player('snare').volume.value = 0;
                players.player('hihat').volume.value = -2; // Softer hi-hat
                players.player('clap').volume.value = 0;
                console.log("Drum samples loaded successfully.");
                resolve();
            },
            onerror: function(error) {
                console.error("Error loading drum samples:", error);
                reject(error);
            }
        }).toDestination();
    });
}
/**
 * Creates and starts the main 16-step drum loop.
 * Assumes Tone.Transport has been started elsewhere.
 */ export function startSequence() {
    if (!isLoaded || sequence) {
        console.warn("Drums not loaded or sequence already started. Cannot start sequence.");
        return;
    }
    sequence = new Tone.Sequence(function(time, step) {
        beatIndex = step; // Update for visualization
        Object.entries(drumPattern).forEach(function(param) {
            var _param = _sliced_to_array(param, 2), drum = _param[0], pattern = _param[1];
            // If the drum is active AND its pattern has a note on this step...
            if (activeDrums.has(drum) && pattern[step]) {
                players.player(drum).start(time);
            }
        });
    }, Array.from({
        length: 16
    }, function(_, i) {
        return i;
    }), "16n").start(0);
    console.log("Drum sequence started.");
}
/**
 * Updates which drums are active based on finger positions.
 * @param {object} fingerStates - An object with finger names as keys and boolean `isUp` as values.
 */ export function updateActiveDrums(fingerStates) {
    activeDrums.clear();
    var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
    try {
        for(var _iterator = Object.entries(fingerStates)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
            var _step_value = _sliced_to_array(_step.value, 2), finger = _step_value[0], isUp = _step_value[1];
            if (isUp) {
                var drum = fingerToDrumMap[finger];
                if (drum) {
                    activeDrums.add(drum);
                }
            }
        }
    } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
    } finally{
        try {
            if (!_iteratorNormalCompletion && _iterator.return != null) {
                _iterator.return();
            }
        } finally{
            if (_didIteratorError) {
                throw _iteratorError;
            }
        }
    }
}
/**
 * Returns the set of currently active drums.
 * @returns {Set<string>} A set of active drum names.
 */ export function getActiveDrums() {
    return activeDrums;
}
/**
 * Returns the mapping of fingers to drums.
 * @returns {object} The finger-to-drum map.
 */ export function getFingerToDrumMap() {
    return fingerToDrumMap;
}
/**
 * Returns the current beat index for external use (like visualization).
 * @returns {number} The current beat index (0-15).
 */ export function getCurrentBeat() {
    return beatIndex;
}
/**
 * Returns the master drum pattern object.
 * @returns {object} The drum pattern.
 */ export function getDrumPattern() {
    return drumPattern;
}