Skip to content
Snippets Groups Projects
Commit 79e7274e authored by RANWEZ Pierre's avatar RANWEZ Pierre :anchor:
Browse files

:sparkles: feat: loop

parent 605c98a9
No related branches found
No related tags found
1 merge request!1✨ feat: CSSLSD V2
...@@ -7,32 +7,44 @@ h1, h2 { ...@@ -7,32 +7,44 @@ h1, h2 {
font-size: [chiffre2 20:100]px; font-size: [chiffre2 20:100]px;
color: rgb([chiffre 0:255],255,255); color: rgb([chiffre 0:255],255,255);
}`; }`;
let parameters = `[[\" \",\"typo\",\"sans-serif;serif;cursive;fantasy\",\"r\",\"note:10\",\"onset:E\"],[\" \",\"chiffre\",\"0:1000\",\"i:100\",\"cc:60\",\"onset:D\"],[\" \",\"chiffre2\",\"0:200\",\"i:10\",\"cc:60\",\"onset:E\"],[\" \",\"couleur\",\"#000:#fff\",\"d\",\"cc:60\",\"loud\"],[\" \",\"opacité\",\"0:1\",\"d\",\"cc:60\",\"hi\"]]`; let parameters = `[[\" \",\"typo\",\"sans-serif;serif;cursive;fantasy\",\"r\",\"note:10\",\"onset:E\"],[\" \",\"chiffre\",\"0:1000\",\"i:100\",\"cc:60\",\"onset:D\"],[\" \",\"chiffre2\",\"0:200\",\"i:10\",\"cc:60\",\"onset:E\"],[\" \",\"couleur\",\"#000:#fff\",\"d\",\"cc:60\",\"loud\"],[\" \",\"opacité\",\"0:1\",\"d\",\"cc:1\",\"hi\"]]`;
let activate = false; let activate = false;
let activateFav = "ressources/icon256.png";
let audioB = false; let audioB = false;
let midiB = false; let midiB = false;
let audioI = false; let audioI = false;
let midiI = false; let midiI = false;
let popup = false; let popup = false;
let loopPlay = false; let loopPlay = false;
let records = [[
{
time: 1,
data: { value: 0, controller: { number: 1 } },
type: 'controlchange'
},
{
time: 200,
data: { value: 1, controller: { number: 1 } },
type: 'controlchange'
}]
];
let all = ""; let all = "";
//Initialize the CSS storage on startup //Initialize the CSS storage on startup
chrome.runtime.onInstalled.addListener(() => { chrome.runtime.onInstalled.addListener(() => {
chrome.storage.sync.set({ css }); chrome.storage.sync.set({ css });
chrome.storage.sync.set({ activate }); chrome.storage.sync.set({ activate });
chrome.storage.sync.set({ activateFav });
chrome.storage.sync.set({ audioB }); chrome.storage.sync.set({ audioB });
chrome.storage.sync.set({ midiB }); chrome.storage.sync.set({ midiB });
chrome.storage.sync.set({ audioI }); chrome.storage.sync.set({ audioI });
chrome.storage.sync.set({ midiI }); chrome.storage.sync.set({ midiI });
chrome.storage.sync.set({ popup }); chrome.storage.sync.set({ popup });
chrome.storage.sync.set({ loopPlay }); chrome.storage.sync.set({ loopPlay });
chrome.storage.sync.set({ records });
chrome.storage.sync.set({ parameters }); chrome.storage.sync.set({ parameters });
chrome.storage.sync.set({ all }); chrome.storage.sync.set({ all });
}); });
/** /**
* @description This function is called when popup is opened and add a listener when user close it. * @description This function is called when popup is opened and add a listener when user close it.
*/ */
...@@ -43,14 +55,3 @@ chrome.runtime.onConnect.addListener(function (port) { ...@@ -43,14 +55,3 @@ chrome.runtime.onConnect.addListener(function (port) {
}); });
} }
}); });
\ No newline at end of file
function loopPlay2() {
console.log('looooop');
}
chrome.runtime.onMessage.addListener((message, callback) => {
// const tabId = getForegroundTabId();
// if (message.data === "loop") {
// chrome.scripting.executeScript({ func: loopPlay2, tabId });
// }
});
\ No newline at end of file
var audioEvents = [];
var midiEvents = [];
var audioContext = null; var audioContext = null;
var meter = null; var meter = null;
var analyser = null; var analyser = null;
...@@ -9,17 +7,6 @@ var buf = new Float32Array(buflen); ...@@ -9,17 +7,6 @@ var buf = new Float32Array(buflen);
var audio = false; var audio = false;
var midi = false; var midi = false;
var audioSample = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var audioSample = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var record = false;
var records = []; // array of recorded values
var recording = {
time: new Date().getTime(),
events: [
[1.0, 'controlchange', '1', 0],
[2.0, 'controlchange', '1', 1],
]
}; // dict with current record
var time;
var playLoop = false;
var parameterSave = {}; var parameterSave = {};
function range(template, value) { function range(template, value) {
...@@ -177,81 +164,13 @@ function midiEvent(type, data) { ...@@ -177,81 +164,13 @@ function midiEvent(type, data) {
}); });
var newTime = new Date().getTime(); if (isRecording) {
bpm = ((1 / ((newTime - time) / 1000)) * 60); const time = Math.floor(performance.now() - recordingTime);
time = newTime; RECORDED[recordCount].push({ type, data, time })
if (record && bpm == 120) {
switch (type) {
case 'controlchange':
recording['events'].push([(newTime - time) / 1000, type, data.controller.name, data.value]);
break;
case 'noteon':
recording['events'].push([(newTime - time) / 1000, type, data.note.numer, data.value]);
break;
case 'pitchbend':
recording['events'].push([(newTime - time) / 1000, type, type, data.value]);
break;
}
} }
} }
// Function that play recorded midi loop
function playMidiLoop(loopId) {
chrome.runtime.sendMessage({ data: 'loop' });
// if (records[loopId]) {
// playLoopInfo = true;
// while (playLoopInfo && playLoop && records[loopId]['events'].length > 0) {
// chrome.storage.sync.get(['loopPlay'], function (result) {
// playLoopInfo = result.loopPlay;
// });
// console.log(playLoopInfo);
// for (let index = 0; index < records[loopId]['events'].length; index++) {
// const event = records[loopId]['events'][index];
// const eventNext = records[loopId]['events'][(index + 1) % records[loopId]['events'].length];
// // !!! TODO: add a way to play midi events
// audioEvents.forEach(event => {
// midiValue = event[3];
// console.log(event[3]);
// templates = event['templates'];
// templates.forEach(template => {
// midiValue = (template['min'] + ((template['max'] - template['min']) * midiValue));
// if (event[1] == 'noteon' && template['eventType'] == 'note' && template['eventName'] == event[2]) {
// value = event['value'].replace('[' + template['templateFull'] + ']', midiValue);
// let els = document.querySelectorAll(event['selector']);
// els.forEach(e => {
// e.style[event['property']] = value; // Note velocity
// });
// }
// if (event[1] == 'controlchange' && template['eventType'] == 'cc' && template['eventName'] == event[2]) {
// value = event['value'].replace('[' + template['templateFull'] + ']', midiValue);
// let els = document.querySelectorAll(event['selector']);
// els.forEach(e => {
// e.style[event['property']] = value; // Control value
// });
// }
// if (event[1] == 'pitchbend' && template['eventType'] == 'pb') {
// value = event['value'].replace('[' + template['templateFull'] + ']', midiValue);
// let els = document.querySelectorAll(event['selector']);
// els.forEach(e => {
// e.style[event['property']] = value; // Pitchbend value
// });
// }
// if (event[1] == 'loud' && template['eventType'] == 'loud') {
// value = event['value'].replace('[' + template['templateFull'] + ']', midiValue);
// let els = document.querySelectorAll(event['selector']);
// els.forEach(e => {
// e.style[event['property']] = value; // Pitchbend value
// });
// }
// });
// });
// sleepFor((event[0] - eventNext[0]) * 1000);
// }
// }
// }
}
function createAudioMeter(audioContext, clipLevel, averaging, clipLag) { function createAudioMeter(audioContext, clipLevel, averaging, clipLag) {
var processor = audioContext.createScriptProcessor(512); var processor = audioContext.createScriptProcessor(512);
processor.onaudioprocess = volumeAudioProcess; processor.onaudioprocess = volumeAudioProcess;
...@@ -338,11 +257,6 @@ function audioApi() { ...@@ -338,11 +257,6 @@ function audioApi() {
}); });
}; };
function sleepFor(sleepDuration) {
var now = new Date().getTime();
while (new Date().getTime() < now + sleepDuration) { /* Do nothing */ }
}
function didntGetStream() { function didntGetStream() {
chrome.storage.sync.set({ audioI: false }); chrome.storage.sync.set({ audioI: false });
audio = false; audio = false;
...@@ -441,7 +355,59 @@ function freqToBin(freq, rounding = 'round') { ...@@ -441,7 +355,59 @@ function freqToBin(freq, rounding = 'round') {
return bin < max ? bin : max; return bin < max ? bin : max;
} }
// Allow to store the current note in an index, for duration computation
const CURRENT = {};
// const RECORDED = [];
chrome.storage.sync.get(['records'], function (result) {
RECORDED = result.records;
});
let recordCount = 0;
let isRecording = false;
let isLoop = false;
let recordingTime = 0;
let theLoop;
const record = (status) => {
isRecording = status;
recordingTime = performance.now();
recordCount = RECORDED.length;
};
// Start loop
const loop = () => {
isLoop = !isLoop;
isRecording = false;
console.log('Loop started', RECORDED);
if (RECORDED[0].length) {
const loopLength = RECORDED[0][RECORDED.length - 1].time;
if (isLoop) {
loopNotes();
theLoop = setInterval(() => loopNotes(), loopLength);
} else {
clearInterval(theLoop)
}
}
};
const loopNotes = () => {
console.log('Looping notes');
RECORDED[0].forEach(note => {
setTimeout(() => {
// Prevent to keep playing also after stop
if (!isLoop) return;
console.log('Looping :p', note.type);
midiEvent(note.type, note.data)
// setTimeout(() => play(note.note, 0), 200)
}, note.time);
})
}
const reset = () => {
RECORDED[0].length = 0;
isRecording = false;
isLoop = false;
}
function audioEvent() { function audioEvent() {
analyser.getFloatTimeDomainData(buf); analyser.getFloatTimeDomainData(buf);
...@@ -485,7 +451,7 @@ function audioEvent() { ...@@ -485,7 +451,7 @@ function audioEvent() {
}); });
const sum = audioSample.reduce((a, b) => a + b, 0); const sum = audioSample.reduce((a, b) => a + b, 0);
const avg = (sum / audioSample.length) |rgba(16 18 27 / 40%)| 0; const avg = (sum / audioSample.length) || 0;
var attack = false; var attack = false;
if (avg + 0.05 < meter.volume) { if (avg + 0.05 < meter.volume) {
attack = true; attack = true;
...@@ -531,13 +497,6 @@ function audioEvent() { ...@@ -531,13 +497,6 @@ function audioEvent() {
} }
}); });
var newTime = new Date().getTime();
bpm = ((1 / ((newTime - time) / 1000)) * 60);
time = newTime;
if (record && bpm == 120) {
recording['events'].push([(newTime - time) / 1000, 'loud', 'data.controller.name', meter.volume * 1.4]);
}
// sleepFor(20);
if (audio) { if (audio) {
rafID = window.requestAnimationFrame(audioEvent); rafID = window.requestAnimationFrame(audioEvent);
} }
...@@ -592,30 +551,25 @@ function onMessage({ type, data }) { ...@@ -592,30 +551,25 @@ function onMessage({ type, data }) {
break; break;
} }
case 'playLoop': { case 'playLoop': {
playLoop = !playLoop; loop();
playMidiLoop(data);
break; break;
} }
case 'getLoop': { case 'getLoop': {
chrome.runtime.sendMessage({ type: 'midiRecords', data: records }); chrome.storage.sync.get(['records'], function (result) {
chrome.runtime.sendMessage({ type: 'midiRecords', data: result.records });
});
break; break;
} }
case 'record': { case 'record': {
record = data; record(data);
// If record in stopped add it to the list of records. break;
if (!record) {
recording['time'] = (new Date().getTime() - recording['time']) / 1000;
records.push(recording);
recording = {
time: new Date().getTime(),
events: []
};
chrome.runtime.sendMessage({ type: 'midiRecords', data: records });
}
else {
time = new Date().getTime();
recording['time'] = new Date().getTime();
} }
case 'resetLoop': {
reset();
chrome.storage.sync.set({ 'records': RECORDED });
chrome.storage.sync.get(['records'], function (result) {
chrome.runtime.sendMessage({ type: 'midiRecords', data: result.records });
});
break; break;
} }
} }
......
...@@ -325,7 +325,7 @@ function onMessage({ type, data }) { ...@@ -325,7 +325,7 @@ function onMessage({ type, data }) {
case 'midiRecords': { case 'midiRecords': {
$('#loopList').text(''); $('#loopList').text('');
for (let i = 0; i < data.length; i++) { for (let i = 0; i < data.length; i++) {
$('#loopList').append('<tr><td>Loop ' + i + '</td><td>' + data[i]['time'] + 'ms</td><td>' + data[i]['events'].length + '</td><td><button id="loopPlay" value="' + i + '">▶️ Play</button></td></tr>'); $('#loopList').append('<tr><td>Loop ' + i + '</td><td>' + data[i][data[i].length - 1].time + 'ms</td><td>' + data[i].length + '</td><td><button id="loopPlay" value="' + i + '">Play</button><button id="loopReset" value="' + i + '">Reset</button></td></tr>');
} }
break; break;
} }
...@@ -402,12 +402,13 @@ $('#record').on('click', function () { ...@@ -402,12 +402,13 @@ $('#record').on('click', function () {
}); });
}); });
$(document).on('click', '#loopPlay', function () { $(document).on('click', '#loopPlay', function () {
if ($(this).text().includes('Play')) { if ($(this).text().includes('Play')) {
$(this).text('⏸️ Pause'); $(this).text('Pause');
chrome.storage.sync.set({ loopPlay: true }); chrome.storage.sync.set({ loopPlay: true });
} else { } else {
$(this).text('▶️ Play'); $(this).text('Play');
chrome.storage.sync.set({ loopPlay: false }); chrome.storage.sync.set({ loopPlay: false });
} }
...@@ -415,7 +416,16 @@ $(document).on('click', '#loopPlay', function () { ...@@ -415,7 +416,16 @@ $(document).on('click', '#loopPlay', function () {
chrome.tabs.query({ active: true, currentWindow: true }, chrome.tabs.query({ active: true, currentWindow: true },
function (tabs) { function (tabs) {
chrome.tabs.sendMessage(tabs[0].id, { type: 'playLoop', data: id }); chrome.tabs.sendMessage(tabs[0].id, { type: 'playLoop', data: id });
}
);
}); });
$(document).on('click', '#loopReset', function () {
id = $(this).val();
chrome.tabs.query({ active: true, currentWindow: true },
function (tabs) {
chrome.tabs.sendMessage(tabs[0].id, { type: 'resetLoop', data: id });
}
);
}); });
$(document).on('click', '.icon-tabler-plus', function () { $(document).on('click', '.icon-tabler-plus', function () {
...@@ -438,7 +448,8 @@ $(document).on('click', '.icon-tabler-minus', function () { ...@@ -438,7 +448,8 @@ $(document).on('click', '.icon-tabler-minus', function () {
// Wait messages from content script // Wait messages from content script
chrome.runtime.onMessage.addListener(onMessage); chrome.runtime.onMessage.addListener(onMessage);
// Indicate to Background that the popup is ready // Indicate to Background that the popup is ready
chrome.runtime.connect({ name: "popup" }); var port = chrome.runtime.connect({ name: "popup" });
// Load the editor // Load the editor
loadEditor(); loadEditor();
// Initialize the settings UI // Initialize the settings UI
......
...@@ -100,7 +100,7 @@ ...@@ -100,7 +100,7 @@
<path d="M20 12v3a3 3 0 0 1 -3 3h-13m3 3l-3 -3l3 -3"></path> <path d="M20 12v3a3 3 0 0 1 -3 3h-13m3 3l-3 -3l3 -3"></path>
</svg> LOOPS </svg> LOOPS
</summary> </summary>
<button id="record">Record</button> BPM : <input id="bpm" type="number" value="120" disabled> <button id="record">Record</button>
<table width="100%"> <table width="100%">
<thead> <thead>
<tr> <tr>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment