Skip to content

Commit

Permalink
Implement multitrack test page
Browse files Browse the repository at this point in the history
- Multitrack page now functional, complete with a lot of new sounds
  • Loading branch information
almic committed Apr 27, 2024
1 parent f353a69 commit ec43c53
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 4 deletions.
Binary file added docs/audio/Equip2.ogg
Binary file not shown.
Binary file added docs/audio/Equip3.ogg
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added docs/audio/forrest_birds_norway-6944-crop.ogg
Binary file not shown.
Binary file added docs/audio/outdoors-walla-20463.ogg
Binary file not shown.
Binary file added docs/audio/pencil-foley-write-1-162850.ogg
Binary file not shown.
Binary file added docs/audio/pencil-foley-write-2-162851.ogg
Binary file not shown.
Binary file added docs/audio/pencil-foley-write-3-162852.ogg
Binary file not shown.
193 changes: 192 additions & 1 deletion docs/js/multitrack.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,194 @@
/**
* Multitrack example
* Multitrack.js
*/

import { toggleText } from './main.js';
import MusicMixer from './lib/MusicMixer.js';
import { AudioRampType } from './lib/automation.js';

/* Web only; loading after interaction with page */
let mixer;
let tracks = {
music: null,
environment: null,
crowd: null,
effects: null,
};
let songList = [
{
path: 'audio/03_Cybercity.ogg',
loopStart: 723_525,
loopEnd: 3_618_386,
},
{
path: 'audio/2000_Shop3.ogg',
loopStart: 37_988,
loopEnd: 1_265_379,
},
{
path: 'audio/Dungeon4.ogg',
loopStart: 0,
loopEnd: 2_945_115,
},
];
let sounds = {
writing: [
'audio/pencil-foley-write-1-162850.ogg',
'audio/pencil-foley-write-2-162851.ogg',
'audio/pencil-foley-write-3-162852.ogg',
],
equip: ['audio/Equip2.ogg', 'audio/Equip3.ogg'],
};
let cache = {};

function loadMixer() {
mixer = new MusicMixer({ latencyHint: 'interactive', sampleRate: 44100 });
mixer.volume(0.5);

const music = mixer.newTrackGroup('music').volume(0.25);
const environment = mixer.newTrackGroup('environment').volume(0.5);
const crowd = mixer.newTrackGroup('crowd').volume(0.5);
const effects = mixer.newTrackGroup('effects').volume(0.5);

const song = songList[0];
music.loadSource(song.path);
music.loop(true, song.loopStart, song.loopEnd);

environment //
.newTrack('wind', 'audio/ambience-wind-blowing-through-trees-01-186986.ogg')
.volume(1.5)
.loop(true);
environment //
.newTrack('birds', 'audio/forrest_birds_norway-6944-crop.ogg')
.volume(2.25)
.loop(true);

crowd //
.newTrack('traffic', 'audio/amb_int_roomtone_traffic_001-57547.ogg')
.volume(3.0)
.loop(true);
crowd //
.newTrack('chatter', 'audio/outdoors-walla-20463.ogg')
.volume(0.5)
.loop(true);

effects.newTrack('writing');
effects.newTrack('gear');

tracks.music = music;
tracks.environment = environment;
tracks.crowd = crowd;
tracks.effects = effects;
}

/* Button functions */

function playAll() {
const buttons = document.querySelectorAll('button[data-track]');
for (const button of buttons) {
if (button.getAttribute('data-track').startsWith('effects')) {
continue;
}

const playing = button.getAttribute('data-playing') == 'true';
if (!playing) {
toggleTrack(button);
}
}
}

function stopAll() {
const buttons = document.querySelectorAll('button[data-track]');
for (const button of buttons) {
const playing = button.getAttribute('data-playing') == 'true';
if (playing) {
toggleTrack(button);
}
}
}

function nextSong(self) {
const next = songList.pop();
songList.unshift(next);
if (!cache[next.path]) {
cache[next.path] = mixer.loadSource(next.path);
}
tracks.music.loadSource(cache[next.path]);
tracks.music.loop(true, next.loopStart, next.loopEnd);
if (self.getAttribute('data-playing') == 'true') {
// This is silly but deliberate
toggleTrack(self);
toggleTrack(self);
}
}

function playSound(self) {
const [groupName, trackName] = self.getAttribute('data-track').split('.');
const track = mixer.trackGroup(groupName)?.track(trackName);
if (track) {
const soundGroup = self.getAttribute('data-sound');
const soundList = sounds[soundGroup];
if (soundList) {
const next = soundList.pop();
soundList.unshift(next);
if (!cache[next]) {
cache[next] = mixer.loadSource(next);
}
track.loadSource(cache[next]);
track.swap({
oldSource: { ramp: AudioRampType.NATURAL, delay: 0, duration: 0.25 },
newSource: { ramp: AudioRampType.NATURAL, delay: 0, duration: 0.01 },
});
}
}
}

function toggleTrack(self) {
const [groupName, trackName] = self.getAttribute('data-track').split('.');
const playing = self.getAttribute('data-playing') == 'true';
const track = mixer.trackGroup(groupName)?.track(trackName) ?? mixer.trackGroup(groupName);
if (track) {
if (playing) {
track.getActiveSource().onended = null;
track.stop({ duration: 2 });
self.setAttribute('data-playing', 'false');
toggleText(self);
} else {
const source = track.getActiveSource() ?? track.getLoadedSource();
const loop = source.loop,
loopStart = source.loopStart * source.sampleRate,
loopEnd = source.loopEnd * source.sampleRate;
track.start({ duration: 2 }).loop(loop, loopStart, loopEnd);
self.setAttribute('data-playing', 'true');
toggleText(self);
track.getActiveSource().addEventListener('ended', () => {
if (self.getAttribute('data-playing') == 'true') {
self.setAttribute('data-playing', 'false');
toggleText(self);
}
});
}
}
}

function changeVolume(self) {
const name = self.getAttribute('data-track');
if (name == 'master') {
mixer.volume(Number(self.value));
return;
}
const track = mixer.track(name);
if (track) {
track.volume(Number(self.value));
}
}

/* Web only; bind functions to global context */

window.loadMixer = loadMixer;
window.playAll = playAll;
window.stopAll = stopAll;
window.nextSong = nextSong;
window.playSound = playSound;
window.toggleTrack = toggleTrack;
window.changeVolume = changeVolume;
11 changes: 8 additions & 3 deletions docs/multitrack.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ <h1 id="title" class="center-text text-glow-responsive">
<span>Master Volume</span>
<input type="range"
min="0" max="1" value="0.5" step="0.001"
oninput="changeVolume('all', Number(this.value))">
data-track="master"
oninput="changeVolume(this)">
<div class="flex-container flex-center flex-grow-children">
<button type="button"
style="margin-right:8px"
Expand All @@ -73,14 +74,18 @@ <h1 id="title" class="center-text text-glow-responsive">
class="flex-container flex-center flex-column height-initial center-text"
>
<span>Music</span>
<input type="range" min="0" max="1" value="0.5" step="0.001" oninput="changeVolume('music',Number(this.value))">
<input type="range"
min="0" max="1" value="0.25" step="0.001"
data-track="music"
oninput="changeVolume(this)"
>
<button type="button"
data-track="music"
data-toggle-text="Stop"
onclick="toggleTrack(this)"
>Start</button>
<button type="button"
onclick="nextSong(this)"
onclick="nextSong(this.previousElementSibling)"
>Next Song</button>
</div>
</div>
Expand Down

0 comments on commit ec43c53

Please sign in to comment.