Skip to content

Commit

Permalink
Merge pull request #15 from bnidevs/starwarswii
Browse files Browse the repository at this point in the history
added sound assignment
  • Loading branch information
starwarswii authored Feb 28, 2020
2 parents 33c3990 + 29aeb66 commit 59904a4
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 63 deletions.
34 changes: 16 additions & 18 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
<!doctype html>
<html>

<head>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.1.3/howler.min.js"></script>

<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.1.3/howler.min.js"></script>

<link href="style.css" rel="stylesheet">
<script type="module" src="js/index.js"></script>
</head>

<body>

<div id="root">
<div id="ctn">

<div id="recordplay-btn-div">
<button id="record-btn"><i id="micIcon" class="fa fa-microphone"></i></button>
<button id="play-btn"><i id="playIcon" class="fa fa-play"></i></button>
</div>

<!-- filled by jquery -->
<table id="grid" />

</div>

<div id="recordPlay">
<button id="recordButton"><i id="recordIcon" class="fa fa-microphone"></i></button>
<button id="playButton"><i id="playIcon" class="fa fa-play"></i></button>
</div>

<input type="file" id="fileInput">

<input id="fileInput" type="file">

<span id="status" style="margin-right: 15px;">no sound</span>
<button id="pendingPlay">play</button>
<button id="assign">assign</button>

<!-- filled by jquery -->
<table id="grid" />

</body>
</html>
</html>
68 changes: 61 additions & 7 deletions public/js/cell.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,45 @@
//each mode is an object that holds
//the mode name as text and a function
//the function says what to do with the sound when you click the cell

//TODO might make more sense for the play function to take a reference to the Cell
//then it could e.g. change how the color toggles with different modes
const modes = {
CUT: "Cut",
OVERLAP: "Overlap",
LOOP: "Loop"
CUT: {
text: "Cut",
play: function(sound) {

//cut stops the current sound before restarting it
if (sound.playing()) {
sound.stop();
}
sound.play();
}
},

OVERLAP: {
text: "Overlap",
play: function(sound) {

//overlap plays the sound on top of the old version
//this is what happens by default with Howler
sound.play();
}
},

LOOP: {
text: "Loop",
play: function(sound) {

//loop pauses or resumes the sound loop
if (sound.playing()) {
sound.pause();
} else {
sound.play();
}

}
}
};

function nextMode(mode) {
Expand Down Expand Up @@ -34,14 +72,19 @@ export default class Cell {
this.hotkey = null;

//TODO
this.audio = null;
this.sound = null;

//TODO does this need to hold more things?
}

setMode(mode) {
this.mode = mode;
this.modeButton.text(mode);
this.modeButton.text(mode.text);

//we need to make sure loop is on if we're in loop mode
if (this.sound !== null) {
this.sound.loop(this.mode === modes.LOOP);
}
}

//changes to the next mode
Expand All @@ -63,6 +106,17 @@ export default class Cell {
this.keyButton.html("&nbsp;");
}

assign(sound) {
//if there was an existing sound, remove it
if (this.sound !== null) {
this.sound.unload();
}

this.sound = sound;
//we need to check this, in case the mode was switched to loop before a sound was loaded
this.sound.loop(this.mode === modes.LOOP);
}

//will be called when the cell is clicked on
//"performs" its action
run() {
Expand All @@ -73,8 +127,8 @@ export default class Cell {

this.cellButton.toggleClass("red");

if (this.audio !== null) {
this.audio.play();
if (this.sound !== null) {
this.mode.play(this.sound);
}
}
}
100 changes: 83 additions & 17 deletions public/js/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Cell from "./cell.js";
import * as Recorder from "./recorder.js";

//dimensions of the cell grid
const GRID_WIDTH = 5;
Expand All @@ -19,6 +20,15 @@ $(function() {
//dictionary from keyboard key to cell object
var hotkeys = {};

//list of Howl objects
//TODO is this needed?
//var sounds = [];
//sound right after uploading or recording
var pendingSound = null;

//if true, currently assigning the pending sound to a cell
var assigning = false;

//called when a cell is clicked
function handleGrid(event, id) {

Expand All @@ -27,13 +37,29 @@ $(function() {
//for whatever reason, clicking on buttons inside the cell
//also triggers this cell click handler
//so we only do stuff if we're clicking on the cell itself
if (!target.hasClass("btbtn")) {
if (!target.hasClass("cell")) {
return;
}

console.log(event);

cells[id].run();
var cell = cells[id];

if (assigning) {

cell.assign(pendingSound);

pendingSound = null;
assigning = false;

//TODO could flesh this out, making buttons disabled at times, etc
$("#assign").text("assign");
$("#status").text("sound assigned to cell "+id);

} else {
cell.run();
}


}

Expand Down Expand Up @@ -85,22 +111,22 @@ $(function() {
//id is 0 to width*height-1
var id = i*GRID_HEIGHT + j;

var cell = $("<div class='btbtn'></div>");
var cell = $("<div class='cell'></div>");
cell.click(eventWithId(handleGrid, id));


var md_button = $("<button class='mdbtn'>Cut</button>");
md_button.click(eventWithId(changeMode, id));
var modeButton = $("<button class='cellButton'>Cut</button>");
modeButton.click(eventWithId(changeMode, id));

var key_button = $("<button id='"+id+"' class='mdbtn keybtn'>&nbsp;</button>");
key_button.click(eventWithId(toggleKeyButton, id));
var keyButton = $("<button class='cellButton keyButton'>&nbsp;</button>");
keyButton.click(eventWithId(toggleKeyButton, id));


//append to array
//this makes the new Cell object have jquery "pointers" to the elements in the dom
cells.push(new Cell(id, cell, md_button, key_button));
cells.push(new Cell(id, cell, modeButton, keyButton));

cell.append(md_button, key_button);
cell.append(modeButton, keyButton);
row.append($("<td/>").html(cell));

}
Expand All @@ -110,7 +136,7 @@ $(function() {



var micIcon = $("#micIcon");
var recordIcon = $("#recordIcon");
var playIcon = $("#playIcon");

var recording = false;
Expand All @@ -123,9 +149,10 @@ $(function() {
// loop: true
// });

/*
function handleRecord(event) {
micIcon.css("color", recording ? "black" : "red");
recordIcon.css("color", recording ? "black" : "red");
recording = !recording;
}
Expand All @@ -150,17 +177,36 @@ $(function() {
playing = !playing;
}
*/


$("#record-btn").click(handleRecord);
$("#play-btn").click(handlePlay);
// $("#recordButton").click(handleRecord);
// $("#playButton").click(handlePlay);

//TODO could probably remove the "Button" suffix on these

$("#recordButton").click(async function() {

if (!Recorder.isRecording()) {
await Recorder.start();

} else {
pendingSound = await Recorder.stop();

$("#status").text("sound from recording loaded");
}

//toggles between the two icons
recordIcon.toggleClass("fa-microphone fa-stop");

});


$("#fileInput").change(function(event) {

console.log("file event fired");

if (event.target.files.length == 0) {
if (event.target.files.length === 0) {
return;
}

Expand All @@ -174,13 +220,17 @@ $(function() {
console.log("in event listener");
var data = reader.result;

var sound = new Howl({
pendingSound = new Howl({
src: data,
// always give file extension: this is optional but helps
format: file.name.split(".").pop().toLowerCase()
});

cells[0].audio = sound;
$("#status").text("sound from upload loaded");

//clear the file chooser text
//$("#fileInput").val("");

//cells[0].audio = sound;

// console.log('playing');
// sound.play();
Expand All @@ -191,6 +241,22 @@ $(function() {

});

$("#pendingPlay").click(function() {
if (pendingSound !== null) {
console.log("playing");
pendingSound.play();
}
});

$("#assign").click(function() {
if (assigning || pendingSound === null) {
return;
}

assigning = true;
$("#assign").text("assigning...");
});

//handle key presses on the page
//if we're waiting for a key, bind it to the waiting cell
//otherwise activate the bound cell, if there is one
Expand Down
57 changes: 57 additions & 0 deletions public/js/recorder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//sets up the audio for recording and returns start and stop functions
const initRecorder = () => new Promise(async resolve => {

const stream = await navigator.mediaDevices.getUserMedia({audio: true});
const mediaRecorder = new MediaRecorder(stream);
console.log(mediaRecorder.mimeType);

const audioChunks = [];

mediaRecorder.addEventListener("dataavailable", event => {
audioChunks.push(event.data);
});

//start recording
const start = () => mediaRecorder.start();

//stop recording and return audio
const stop = () => new Promise(resolve => {

mediaRecorder.addEventListener("stop", () => {

const audioBlob = new Blob(audioChunks);
const audioUrl = URL.createObjectURL(audioBlob);

const audio = new Howl({
src: audioUrl,
format: "webm"
});

//return the sound
resolve(audio);
});

mediaRecorder.stop();
});

//return the start and stop functions
//this is the same as {start: start, stop: stop}
resolve({start, stop});
});

let recorder = null;

export async function start() {
recorder = await initRecorder();
recorder.start();
}

export async function stop() {
let audio = await recorder.stop();
recorder = null;
return audio;
}

export function isRecording() {
return recorder !== null;
}
Loading

0 comments on commit 59904a4

Please sign in to comment.