fix playing multiple recordings with audio and more
dependencies hashes: openFrameworks d78075f4bca6be2a2533c6e51a75cc1f18404501 ofxMsdfgen e14da13d02c4dff04fb69d7923469f606924e6c3 ofxGPUFont d482bb7cbdf6b296fa4ab5abcf73fb5ff8c8b239 ofxVariableLab 0b5f9bdebc1e5550621957e73c040c258ec6317b ofxProfiler a868e34fa1a79189dd4fbdede2938e308535e5e8 theatre 78a67ee6650d846fe5cc4770770b1511328033e6
This commit is contained in:
parent
8750151b7d
commit
32778138ba
6 changed files with 113 additions and 64 deletions
|
@ -105,18 +105,14 @@ const MicrophoneRecorder = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.startListener = (event) => {
|
this.startListener = (event) => {
|
||||||
console.log('microphoneRecorder startl received', event);
|
|
||||||
if (event.detail === record.possibleStates.RECORDING) {
|
if (event.detail === record.possibleStates.RECORDING) {
|
||||||
this.start();
|
this.start();
|
||||||
console.log('microphoneRecorder start', filenameWithoutExtension);
|
|
||||||
window.removeEventListener('record', this.startListener);
|
window.removeEventListener('record', this.startListener);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.stopListener = (event) => {
|
this.stopListener = (event) => {
|
||||||
console.log('microphoneRecorder stopl received', event);
|
|
||||||
if (event.detail === record.possibleStates.STOPPING_RECORDING) {
|
if (event.detail === record.possibleStates.STOPPING_RECORDING) {
|
||||||
console.log('microphoneRecorder stop', filenameWithoutExtension);
|
|
||||||
this.stop().then((filename) => {
|
this.stop().then((filename) => {
|
||||||
// be happy
|
// be happy
|
||||||
});
|
});
|
||||||
|
@ -991,25 +987,7 @@ const Audio = function(tp, record) {
|
||||||
audioElement.classList.add(toCssClass(`audio_file${file}`));
|
audioElement.classList.add(toCssClass(`audio_file${file}`));
|
||||||
document.querySelector('body').append(audioElement);
|
document.querySelector('body').append(audioElement);
|
||||||
|
|
||||||
const arr = FS.readFile(`${config.fs.idbfsAudioDir}/${file}`);
|
const src = moduleFS.objectUrl(`${config.fs.idbfsAudioDir}/${file}`);
|
||||||
let type = 'audio/wav';
|
|
||||||
const filesplit = file.split('.');
|
|
||||||
const extension = filesplit[filesplit.length - 1];
|
|
||||||
if (extension === 'wav') {
|
|
||||||
type = 'audio/wav';
|
|
||||||
} else if (extension === 'mp3') {
|
|
||||||
type = 'audio/mpeg';
|
|
||||||
} else if (extension === 'ogg') {
|
|
||||||
type = 'audio/ogg';
|
|
||||||
} else if (extension === 'webm') {
|
|
||||||
type = 'audio/webm';
|
|
||||||
}
|
|
||||||
|
|
||||||
const src = URL.createObjectURL(
|
|
||||||
new Blob([arr], {
|
|
||||||
type
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
audioElement.src = src;
|
audioElement.src = src;
|
||||||
audioElement.loop = true;
|
audioElement.loop = true;
|
||||||
|
|
|
@ -32,14 +32,17 @@ const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) {
|
||||||
keyframes: [{
|
keyframes: [{
|
||||||
position: -1,
|
position: -1,
|
||||||
value: false,
|
value: false,
|
||||||
|
type: 'hold',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
position: start,
|
position: start,
|
||||||
value: true,
|
value: true,
|
||||||
|
type: 'hold',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
position: stop,
|
position: stop,
|
||||||
value: false,
|
value: false,
|
||||||
|
type: 'hold',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}];
|
}];
|
||||||
|
|
|
@ -1,48 +1,81 @@
|
||||||
import {
|
import {
|
||||||
clone,
|
clone,
|
||||||
|
sanitizeTheatreKey,
|
||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
|
|
||||||
const AudioPlayer = function() {
|
const AudioPlayer = function() {
|
||||||
const audioElements = [];
|
const audioElements = [];
|
||||||
let updateInterval = false;
|
let updateInterval = false;
|
||||||
let updateInterval_ms = 10;
|
let updateInterval_ms = 10;
|
||||||
this.add = (layer, propTitle, time, file) => {
|
|
||||||
|
const getAudioID = (filename) => {
|
||||||
|
let audioID = sanitizeTheatreKey(filename);
|
||||||
|
const duplicate = audioElements.findIndex((e) => e.audioID === audioID) !== -1;
|
||||||
|
if (duplicate) {
|
||||||
|
let index = 0;
|
||||||
|
let unique = false;
|
||||||
|
while (!unique) { // uuuh, while loops..
|
||||||
|
const newAudioID = `${audioID}_${index}`;
|
||||||
|
if (audioElements.findIndex((e) => e.audioID === newAudioID) === -1) {
|
||||||
|
audioID = newAudioID;
|
||||||
|
unique = true;
|
||||||
|
} else {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return audioID
|
||||||
|
}
|
||||||
|
return audioID;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.addMany = (manyAudioElements) => {
|
||||||
|
manyAudioElements.forEach((e) => {
|
||||||
|
this.add(e.audioID, e.layerID, e.propTitle, e.file);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.add = (audioID, layer, propTitle, file, startTime) => {
|
||||||
const layerID = typeof layer === 'string' ? layer : layer.id();
|
const layerID = typeof layer === 'string' ? layer : layer.id();
|
||||||
propTitle = Array.isArray(propTitle) ? propTitle.join('.') : propTitle;
|
propTitle = Array.isArray(propTitle) ? propTitle.join('.') : propTitle;
|
||||||
console.log('AudioPlayer::add',{layerID, propTitle, time, file});
|
|
||||||
const index = audioElements.findIndex((e) => e.layerID === layerID && e.propTitle === propTitle);
|
if (!audioID) {
|
||||||
if (index === -1) {
|
audioID = getAudioID(file);
|
||||||
const audioDomElement = document.createElement('audio');
|
|
||||||
audioDomElement.classList.add('invisible');
|
|
||||||
audioDomElement.classList.add('audio_file');
|
|
||||||
audioDomElement.src = audio.audioSourceCombos[file].audioElement.src;
|
|
||||||
audioElements.push({
|
|
||||||
layerID, propTitle, audioDomElement, time, file
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
audioElements[index].src = audio.audioSourceCombos[file].audioDomElement.src;
|
|
||||||
audioElements[index].time = time;
|
|
||||||
}
|
}
|
||||||
|
const audioDomElement = new Audio(moduleFS.objectUrl(`${config.fs.idbfsAudioDir}/${file}`));
|
||||||
|
audioDomElement.loop = true;
|
||||||
|
audioDomElement.load();
|
||||||
|
//const audioDomElement = document.createElement('audio');
|
||||||
|
//audioDomElement.classList.add('invisible');
|
||||||
|
//audioDomElement.classList.add('audio_file');
|
||||||
|
//audioDomElement.classList.add('audioPlayer');
|
||||||
|
//audioDomElement.src = moduleFS.objectUrl(`${config.fs.idbfsAudioDir}/${file}`);
|
||||||
|
audioDomElement.loop = true;
|
||||||
|
audioElements.push({
|
||||||
|
audioID,
|
||||||
|
layerID,
|
||||||
|
propTitle,
|
||||||
|
audioDomElement,
|
||||||
|
file,
|
||||||
|
startTime
|
||||||
|
});
|
||||||
};
|
};
|
||||||
this.update = () => {
|
this.update = () => {
|
||||||
audioElements.forEach((audioElement, i) => {
|
audioElements.forEach((audioElement, i) => {
|
||||||
if (tp.isPlaying() && !record.isRecording()) {
|
if (tp.isPlaying() && !record.isRecording()) {
|
||||||
const diff = tp.sheet.sequence.position - audioElement.time;
|
const shouldBePlaying = getAudioLayer().theatreObject.value[audioElement.audioID];
|
||||||
if (diff >= 0) {
|
if (shouldBePlaying && audioElement.audioDomElement.paused) {
|
||||||
if (audioElement.audioDomElement.paused) {
|
// sequence position is always greater than startTime
|
||||||
|
// this is true, as it is written
|
||||||
|
const diff = tp.sheet.sequence.position - audioElement.startTime;
|
||||||
audioElement.audioDomElement.currentTime = diff;
|
audioElement.audioDomElement.currentTime = diff;
|
||||||
audioElement.audioDomElement.play();
|
audioElement.audioDomElement.play();
|
||||||
console.log('play audioElement ', audioElement.file, audioElement.propTitle, i);
|
} else if (!shouldBePlaying && !audioElement.audioDomElement.paused) {
|
||||||
|
audioElement.audioDomElement.pause();
|
||||||
|
audioElement.audioDomElement.currentTime = 0;
|
||||||
}
|
}
|
||||||
} else if (!audioElement.audioDomElement.paused) {
|
} else if (!audioElement.audioDomElement.paused) {
|
||||||
audioElement.audioDomElement.pause();
|
audioElement.audioDomElement.pause();
|
||||||
audioElement.audioDomElement.currentTime = 0;
|
audioElement.audioDomElement.currentTime = 0;
|
||||||
console.log('pause audioElement ', audioElement.file, audioElement.propTitle, i);
|
|
||||||
}
|
|
||||||
} else if (!audioElement.audioDomElement.paused) {
|
|
||||||
audioElement.audioDomElement.pause();
|
|
||||||
audioElement.audioDomElement.currentTime = 0;
|
|
||||||
console.log('pausé audioElement ', audioElement.file, audioElement.propTitle, i);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -54,11 +87,11 @@ const AudioPlayer = function() {
|
||||||
}, updateInterval_ms);
|
}, updateInterval_ms);
|
||||||
};
|
};
|
||||||
let hot = false;
|
let hot = false;
|
||||||
let time = false;
|
let startTime = false;
|
||||||
this.listener = (event) => {
|
this.listener = (event) => {
|
||||||
if (event.detail === record.possibleStates.RECORDING) {
|
if (event.detail === record.possibleStates.RECORDING) {
|
||||||
hot = clone(record.getHot());
|
hot = clone(record.getHot());
|
||||||
time = tp.sheet.sequence.position;
|
startTime = tp.sheet.sequence.position;
|
||||||
const layerIDs = Object.keys(hot);
|
const layerIDs = Object.keys(hot);
|
||||||
layerIDs.forEach((layerID) => {
|
layerIDs.forEach((layerID) => {
|
||||||
const propTitles = Object.keys(hot[layerID]);
|
const propTitles = Object.keys(hot[layerID]);
|
||||||
|
@ -68,8 +101,10 @@ const AudioPlayer = function() {
|
||||||
if (m.source === 'microphone') {
|
if (m.source === 'microphone') {
|
||||||
const waitForMicrophoneListener = (event) => {
|
const waitForMicrophoneListener = (event) => {
|
||||||
if (event.detail.fileIsRead) {
|
if (event.detail.fileIsRead) {
|
||||||
this.add(layerID, propTitle, time, event.detail.filename);
|
const filename = event.detail.filename;
|
||||||
addAudioLayerTrack(event.detail.filename, time, tp.sheet.sequence.position);
|
const audioID = getAudioID(filename);
|
||||||
|
this.add(audioID, layerID, propTitle, filename, startTime);
|
||||||
|
addAudioLayerTrack(audioID, startTime, tp.sheet.sequence.position);
|
||||||
window.removeEventListener(
|
window.removeEventListener(
|
||||||
'microphoneRecorder',
|
'microphoneRecorder',
|
||||||
waitForMicrophoneListener);
|
waitForMicrophoneListener);
|
||||||
|
@ -91,9 +126,13 @@ const AudioPlayer = function() {
|
||||||
const m = audio.getSavedMapping()[layerID][propTitle];
|
const m = audio.getSavedMapping()[layerID][propTitle];
|
||||||
if (m.addToTimeline) {
|
if (m.addToTimeline) {
|
||||||
if (m.source === 'microphone') {
|
if (m.source === 'microphone') {
|
||||||
|
// handled above, as we need to wait for the microphone recording to be written and read
|
||||||
|
// and we rather start waiting, when it has definitely not happened yet
|
||||||
} else {
|
} else {
|
||||||
this.add(layerID, propTitle, time, m.source);
|
const filename = m.source;
|
||||||
addAudioLayerTrack(m.source, time, tp.sheet.sequence.position);
|
const audioID = getAudioID(filename);
|
||||||
|
this.add(audioID, layerID, propTitle, filename, startTime);
|
||||||
|
addAudioLayerTrack(audioID, startTime, tp.sheet.sequence.position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -105,7 +105,7 @@ const getAbout = () => {
|
||||||
const buttonExp = textParent.querySelector(".expandText");
|
const buttonExp = textParent.querySelector(".expandText");
|
||||||
|
|
||||||
if (buttonExp === null) {
|
if (buttonExp === null) {
|
||||||
console.error("Could not find .expandText within .textParent");
|
console.error("Main::getAbout","Could not find .expandText within .textParent");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,6 +463,11 @@ window.getAudioLayers = () => {
|
||||||
return audioLayers;
|
return audioLayers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// for now we changed the design to have only one audio layer
|
||||||
|
window.getAudioLayer = () => {
|
||||||
|
return audioLayers.length > 0 ? audioLayers[0] : false;
|
||||||
|
};
|
||||||
|
|
||||||
window.getLayer = (layerID = tp.studio.selection[0].address.objectKey) => {
|
window.getLayer = (layerID = tp.studio.selection[0].address.objectKey) => {
|
||||||
if (layerID === 'artboard') {
|
if (layerID === 'artboard') {
|
||||||
return artboard;
|
return artboard;
|
||||||
|
@ -590,7 +595,6 @@ const addAudioLayer = (filename = false) => {
|
||||||
}
|
}
|
||||||
return `audio-${index}`;
|
return `audio-${index}`;
|
||||||
})();
|
})();
|
||||||
console.log('adding', audioLayerID);
|
|
||||||
const audioLayer = new AudioLayer(tp, audioLayerID, filename, false);
|
const audioLayer = new AudioLayer(tp, audioLayerID, filename, false);
|
||||||
layersById[audioLayerID] = audioLayer;
|
layersById[audioLayerID] = audioLayer;
|
||||||
audioLayers.push(audioLayer);
|
audioLayers.push(audioLayer);
|
||||||
|
@ -716,7 +720,6 @@ const initPanels = () => {
|
||||||
moduleFS
|
moduleFS
|
||||||
.save(file)
|
.save(file)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log('ermh... done uploading?', file);
|
|
||||||
audio.readAudioFiles();
|
audio.readAudioFiles();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -60,7 +60,6 @@ const ModuleFS = function() {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
if (file.type.indexOf('font') >= 0 || file.hasOwnProperty('isFont') && file.isFont === true) {
|
if (file.type.indexOf('font') >= 0 || file.hasOwnProperty('isFont') && file.isFont === true) {
|
||||||
var uint8View = new Uint8Array(file.arrayBuffer);
|
var uint8View = new Uint8Array(file.arrayBuffer);
|
||||||
console.log('trying to save the font file, file, uint8View', file, uint8View);
|
|
||||||
if (!FS.analyzePath(`${config.fs.idbfsFontDir}/${file.name}`).exists) {
|
if (!FS.analyzePath(`${config.fs.idbfsFontDir}/${file.name}`).exists) {
|
||||||
FS.createDataFile(config.fs.idbfsFontDir, file.name, uint8View, true, true);
|
FS.createDataFile(config.fs.idbfsFontDir, file.name, uint8View, true, true);
|
||||||
}
|
}
|
||||||
|
@ -71,7 +70,6 @@ const ModuleFS = function() {
|
||||||
} else if (file.type.indexOf('zip') >= 0 || file.hasOwnProperty('isZip') && file.isZip === true) {
|
} else if (file.type.indexOf('zip') >= 0 || file.hasOwnProperty('isZip') && file.isZip === true) {
|
||||||
var uint8View = new Uint8Array(file.arrayBuffer);
|
var uint8View = new Uint8Array(file.arrayBuffer);
|
||||||
var filePath = `${config.fs.idbfsTmpDir}/${file.name}`;
|
var filePath = `${config.fs.idbfsTmpDir}/${file.name}`;
|
||||||
console.log(filePath);
|
|
||||||
if (!FS.analyzePath(filePath).exists) {
|
if (!FS.analyzePath(filePath).exists) {
|
||||||
FS.createDataFile(config.fs.idbfsTmpDir, file.name, uint8View, true, true);
|
FS.createDataFile(config.fs.idbfsTmpDir, file.name, uint8View, true, true);
|
||||||
}
|
}
|
||||||
|
@ -81,7 +79,6 @@ const ModuleFS = function() {
|
||||||
});
|
});
|
||||||
} else if (file.type.indexOf('audio') === 0) {
|
} else if (file.type.indexOf('audio') === 0) {
|
||||||
var uint8View = new Uint8Array(file.arrayBuffer);
|
var uint8View = new Uint8Array(file.arrayBuffer);
|
||||||
console.log('trying to save the audio file, file, uint8View', file, uint8View);
|
|
||||||
if (!FS.analyzePath(`${config.fs.idbfsAudioDir}/${file.name}`).exists) {
|
if (!FS.analyzePath(`${config.fs.idbfsAudioDir}/${file.name}`).exists) {
|
||||||
FS.createDataFile(config.fs.idbfsAudioDir, file.name, uint8View, true, true);
|
FS.createDataFile(config.fs.idbfsAudioDir, file.name, uint8View, true, true);
|
||||||
this.syncfs(MODE_WRITE_TO_PERSISTENT)
|
this.syncfs(MODE_WRITE_TO_PERSISTENT)
|
||||||
|
@ -114,6 +111,33 @@ const ModuleFS = function() {
|
||||||
resolve(false);
|
resolve(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const objectUrls = {};
|
||||||
|
this.objectUrl = (filePath) => {
|
||||||
|
if (typeof objectUrls[filePath] === 'undefined') {
|
||||||
|
const arr = FS.readFile(filePath);
|
||||||
|
let type = 'audio/wav';
|
||||||
|
const filesplit = filePath.split('.');
|
||||||
|
const extension = filesplit[filesplit.length - 1];
|
||||||
|
|
||||||
|
// is there a way to get mime type without guessing by extension?
|
||||||
|
if (extension === 'wav') {
|
||||||
|
type = 'audio/wav';
|
||||||
|
} else if (extension === 'mp3') {
|
||||||
|
type = 'audio/mpeg';
|
||||||
|
} else if (extension === 'ogg') {
|
||||||
|
type = 'audio/ogg';
|
||||||
|
} else if (extension === 'webm') {
|
||||||
|
type = 'audio/webm';
|
||||||
|
}
|
||||||
|
objectUrls[filePath] = URL.createObjectURL(
|
||||||
|
new Blob([arr], {
|
||||||
|
type
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return objectUrls[filePath];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|
|
@ -457,13 +457,15 @@ const toCssClass = (text, prefix = '') => {
|
||||||
;
|
;
|
||||||
return cssClass;
|
return cssClass;
|
||||||
};
|
};
|
||||||
const sanitizeTheatreKey = (key) => {
|
const sanitizeTheatreKey = (key, removeExtension = true) => {
|
||||||
let theatreKey = key;
|
let theatreKey = key;
|
||||||
|
if (removeExtension) {
|
||||||
theatreKey = theatreKey.split('.');
|
theatreKey = theatreKey.split('.');
|
||||||
if (theatreKey.length > 1) {
|
if (theatreKey.length > 1) {
|
||||||
theatreKey.pop();
|
theatreKey.pop();
|
||||||
}
|
}
|
||||||
theatreKey = theatreKey.join('');
|
theatreKey = theatreKey.join('');
|
||||||
|
}
|
||||||
if (theatreKey.substr(0, 1).match(/^([0-9])$/i)) {
|
if (theatreKey.substr(0, 1).match(/^([0-9])$/i)) {
|
||||||
theatreKey = `t_${theatreKey}`;
|
theatreKey = `t_${theatreKey}`;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue