Reusing a function for buttons that work independently of each other? - audio

I'm trying to create something with P5.js that resembles an audio looper—that is, you record a snippet of audio, it plays back to you as a loop, and then you can record other snippets of audio to play together to create a song.
I figured out how to record audio, play it back as a loop, and stop the loop, but I'm not sure the best way to repeat that function so that it can be used for buttons that function independently of each other and record separate audio files, as I would like to record multiple loops.
I'm still pretty new to P5.js, so there's probably a simple way to do this—any ideas help! In general, if you have any ideas on how to achieve this project as a whole (the audio looper) I'd love to hear them.
This is my code:
let mic, recorder, soundFile, button;
let state = 0;
function setup() {
createCanvas(windowWidth, windowHeight);
background(200);
mic = new p5.AudioIn();
mic.start();
recorder = new p5.SoundRecorder();
recorder.setInput(mic);
soundFile = new p5.SoundFile();
button = createButton("record");
button.size(200, 100);
button.style("font-family", "Bodoni");
button.style("font-size", "48px");
button.position(10, 10, 10);
button.mouseClicked(loopRecord);
}
// this is the looper
function loopRecord() {
if (state === 0 && mic.enabled) {
recorder.record(soundFile);
background(255, 0, 0);
state++;
} else if (state === 1) {
recorder.stop();
background(0, 255, 0);
state++;
} else if (state === 2) {
soundFile.loop();
state++;
} else if (state === 3) {
soundFile.stop();
state++;
} else if (state === 4) {
state === 0;
}
}

You should somehow structure your data so that each button has its own state (and other parameters that should not be global, but instead unique to each loop).
Here an example using an array of track objects:
https://editor.p5js.org/RemyDekor/sketches/gM75vBYmk
I'll copy the code here as well
let mic
// this array will be filled afterwards
let tracksArray = [];
function setup() {
createCanvas(400, 400);
background(200);
// we need only one mic (it is still global)
mic = new p5.AudioIn();
mic.start();
// we call a function that creates a custom "track" object and puts it in the tracksArray (which you could use for some other things, but is currently un-used)
createTrack();
// we create a button that call the same function when we click on it
const addTrackButton = createButton("add track");
addTrackButton.mouseClicked(createTrack)
addTrackButton.position(10, 10)
}
// We now use names (strings) instead of abstract numbers to set the state of the track
function handleTrackButtonClick(trackObject) {
if (trackObject.state === "idle" && mic.enabled) {
trackObject.recorder.record(trackObject.soundFile);
background(255, 0, 0);
trackObject.state = "recording";
console.dir(trackObject.button.elt.innerText = "[recording..]");
} else if (trackObject.state === "recording") {
trackObject.recorder.stop();
background(0, 255, 0);
trackObject.state = "stopped";
console.dir(trackObject.button.elt.innerText = "play");
} else if (trackObject.state === "stopped") {
trackObject.soundFile.loop();
trackObject.state = "playing";
console.dir(trackObject.button.elt.innerText = "[playing..] stop")
} else if (trackObject.state === "playing") {
trackObject.soundFile.stop();
trackObject.state = "stopped";
console.dir(trackObject.button.elt.innerText = "[stopped..] play")
}
}
function createTrack() {
const newButton = createButton("record");
newButton.style("font-family", "Bodoni");
newButton.style("font-size", "48px");
// we do not position this button anymore, and use the "flow" of the html document
newButton.style("display", "block");
// this is the "track" object we create, and we attach the previously global parameters/states on it
const newTrackObject = {
button: newButton,
state: "idle",
recorder: new p5.SoundRecorder(),
soundFile: new p5.SoundFile()
};
newButton.mouseClicked(function() {
handleTrackButtonClick(newTrackObject)
});
newTrackObject.recorder.setInput(mic);
tracksArray.push(newTrackObject);
}

Related

Flutter - how do I get the duration of a picked video file on Web?

I've tried everything and failed to determine the duration of a picked video file on Flutter Web. All libraries on pub.dev need a 'File' and this is not available on the web.
I've not been able to get this from the metadata either.
What worked for me, though I am unhappy with the solution approach is:
Widget buildHiddenVideoPlayer(Key key) {
var _videoElement = html.VideoElement();
_videoElement.id = 'htmlHiddenVideoID';
_videoElement.autoplay = true;
_videoElement.muted = true;
_videoElement.loop = true;
_videoElement.controls = false;
_videoElement.defaultMuted = true;
if (fileData != null) {
_videoElement.src = xfile.path; // where xfile is the file picked as XFile
}
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
'htmlHiddenVideoID',
(int viewId) => _videoElement,
);
return HtmlElementView(
key: key,
viewType: 'htmlHiddenVideoID',
);
}
This widget is hidden in a 5 x 5 sized box behind a iFrame widget (in my implementation)
Then when I need the duration of a picked file:
VideoElement element = document.getElementById('htmlHiddenVideoID') as VideoElement;
setState(() {
element.src = pickedFile.path;
});
while (true) {
await Future.delayed(const Duration(milliseconds: 200), () {});
duration = element.duration;
if (!duration.isNaN) break; // duration is not returned immediately in many cases
}
element.pause(); // stops the hidden video from playing and consuming resources

Prevent nested lists in text-editor (froala)

I need to prevent/disable nested lists in text editor implemented in Angular. So far i wrote a hack that undos a nested list when created by the user. But if the user creates a normal list and presses the tab-key the list is shown as nested for a few milliseconds until my hack sets in back to a normal list. I need something like event.preventDefault() or stopPropagation() on tab-event keydown but unfortunately that event is not tracked for some reason. Also the froala settings with tabSpaces: falseis not showing any difference when it comes to nested list...in summary i want is: if the user creates a list and presses the tab-key that nothing happens, not even for a millisecond. Has anyone an idea about that?
Froala’s support told us, there’s no built-in way to suppress nested list creation. They result from TAB key getting hit with the caret on a list item. However we found a way to get around this using MutationObserver
Basically we move the now nested list item to his former sibling and remove the newly created list. Finally we take care of the caret position.
var observer = new MutationObserver(mutationObserverCallback);
observer.observe(editorNode, {
childList: true,
subtree: true
});
var mutationObserverCallback = function (mutationList) {
var setCaret = function (ele) {
if (ele.nextSibling) {
ele = ele.nextSibling;
}
var range = document.createRange();
var sel = window.getSelection();
range.setStart(ele, 0);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
};
var handleAddedListNode = function (listNode) {
if (! listNode.parentNode) {
return;
}
var parentListItem = listNode.parentNode.closest('li');
if (!parentListItem) {
return;
}
var idx = listNode.children.length - 1;
while (idx >= 0) {
var childNode = listNode.children[idx];
if (parentListItem.nextSibling) {
parentListItem.parentNode.insertBefore(childNode, parentListItem.nextSibling);
} else {
parentListItem.parentNode.appendChild(childNode);
}
--idx;
}
setCaret(parentListItem);
listNode.parentNode.removeChild(listNode);
};
mutationList.forEach(function (mutation) {
var addedNodes = mutation.addedNodes;
if (!addedNodes.length) {
return;
}
for (var i = 0; i < addedNodes.length; i++) {
var currentNode = addedNodes[i];
switch (currentNode.nodeName.toLowerCase()) {
case 'ol':
case 'ul':
handleAddedListNode(currentNode);
break;
// more optimizations
}
}
})
};

Phaserjs, sprite overlap, not working

I am new to Phaserjs, trying to create basic drag-drop style game.
I have created the game and add arcade physics (this.game.physics.arcade.enable(this.orange_outline);)
Currently overlap happen as soon as the edges collide.
I want to detect that my code should trigger when 50% overlap happen. is it possible in phaserjs?
var GameState = {
init:function(){
this.physics.startSystem(Phaser.Physics.ARCADE);
},
create: function () {
this.background = this.game.add.sprite(0, 0, 'background');
this.overlapHappen = false;
this.orange_outline = this.game.add.sprite(459,199,'orange_outline');
this.orange_outline.frame = 2;
this.orange_outline.anchor.setTo(.5);
this.orange_outline.customParams = {myName:'orange_outline',questionImg:'orange'};
this.orange_inner = this.game.add.sprite(150,197,'orange_inner');
this.orange_inner.anchor.setTo(.5);
this.orange_inner.customParams = {myName:'orange_inner',questionImg:'orange',targetKey:this.orange_outline,targetImg:'orange_outline'};
this.orange_inner.frame = 1;
this.orange_inner.inputEnabled = true;
this.orange_inner.input.enableDrag();
this.orange_inner.input.pixelPerfectOver = true;
this.orange_inner.events.onDragStart.add(this.onDragStart,this);
// this.game.physics.enable(this.orange_inner,Phaser.Physics.ARCADE);
this.game.physics.arcade.enable(this.orange_inner);
this.game.physics.arcade.enable(this.orange_outline);
this.orange_inner.events.onDragStop.add(this.onDragStop,this);
},
update: function () {
//this.orange.animations.play('orange_one',1)
},
onDragStart:function(sprite,pointer){
//console.log(sprite.key + " dragged")
},
onDragStop:function(sprite,pointer){
var endSprite = sprite.customParams.targetKey;
//console.log(sprite.customParams);
this.stopDrag(sprite,endSprite)
},
stopDrag:function(currentSprite,endSprite){
if (!this.game.physics.arcade.overlap(currentSprite, endSprite, function() {
var currentSpriteTarget = currentSprite.customParams.targetImg;
var endSpriteName = endSprite.customParams.myName;
if(currentSpriteTarget === endSpriteName){
currentSprite.input.draggable = false;
currentSprite.position.copyFrom(endSprite.position);
currentSprite.anchor.setTo(endSprite.anchor.x, endSprite.anchor.y);
}
console.log(currentSpriteTarget,endSpriteName);
})) {
//currentSprite.position.copyFrom(currentSprite.originalPosition);
console.log('you')
}
}
}
In stopDrag() I am detecting overlap.
You can try to get the amount of horizontal and vertical overlap amount and check if it satisfies a certain threshold. This can be done in additional overlap function callback, that is called processCallback in documentation. As an example:
if (!this.game.physics.arcade.overlap(currentSprite, endSprite, function() {
//your callback !
},function() {
if (this.game.physics.arcade.getOverlapX(currentSprite, endSprite) > currentSprite.width / 2
&& this.game.physics.arcade.getOverlapY(currentSprite, endSprite) > currentSprite.height / 2) {
//Overlaping !
return true;
} else {
//as if no overlap occured
return false;
}
},this) {
//
}
Another way to do this (other than what Hamdi Douss offers) is to resize your body to only take up 50% of the area. This will automatically ensure that collisions/overlap don't occur unless the reduced bodies touch each other.
To view your current body, use Phaser's debug methods
this.game.debug.body(someSprite, 'rgba(255,0,0,0.5)');

How to control relays using Raspberry PI and Nodejs?

I am using the watch method from the onoff module to watch to status of the input, the callback function will be called for any change in the input (from 0 to 1 or from 1 to 0) which is what I want.
The problem is when I first run the application if the main is on (inputMain is 1 ) or the main is off (inputMain is 0 ) the callback function is not executed because there is no change in the value of the input.
So if the main is on I can't call the main() function until it becomes off then on, this problem only happens when I first run the application.
How do I get around this ? Is there a better approach to handle relays ?
var GPIO = require('onoff').Gpio,
inputMain = new GPIO(17,'in','both'),
inputGen1 = new GPIO(4,'in','both'),
inputGen2 = new GPIO(27,'in','both'),
inputGen3 = new GPIO(22,'in','both'),
outMain = new GPIO(11,'high'),
outGen1 = new GPIO(15,'high'),
outGen2P = new GPIO(18,'high'), // Generator 2 power
outGen2SM = new GPIO(23,'high'), //Generator 2 starting motor
outGen2 = new GPIO(24,'high'), // Generator 2 contactor
outGen3P = new GPIO(25,'high'),
outGen3SM = new GPIO(8,'high'),
outGen3 = new GPIO(7,'high'),
objects =[outMain,outGen1,outGen2P,outGen2SM,outGen2,outGen3P,outGen3SM,outGen3];
// Checking if there is main or not which is the refrence for all other power sources
inputMain.watch(function(err,state){
if (state)
main(1);
});
// Switch to Main contactor
function main (arg) {
console.log('test');
if (arg == 1) {
value = [0,1,1,1,1,1,1,1];}
else {
value = [0,0,0,0,0,0,0,0];
}
out(value);
}
// Turn on all the relays depending on values of the array ...
function out(value) {
for ( var i = 0; i< value.length; i++) {
if (value[i] == 0 ) {
var a = objects[i];
} else {
objects[i].writeSync(value[i]);
}
}
setTimeout(function() {
a.writeSync(0);
},5000);
}
I'm afraid you will need to call read or readSync for that.
...
outGen3SM = new GPIO(8,'high'),
outGen3 = new GPIO(7,'high'),
objects =[outMain,outGen1,outGen2P,outGen2SM,outGen2,outGen3P,outGen3SM,outGen3];
//Forces the first output update
main(inputMain.readSync());

CTreeCtrl: How to clear the focus of selected item

Am new to MFC, I want to replicate the exact Ctrl+Page Down and Ctrl+Page Up behavior to regular Page Down/Page Up keys without any supporting keys (Ctrl/Shift). I have been trying to clear the focus of item which is getting selected automatically on striking the keys Page Up and Page Down.
I've tried with this code but its not working:
case VK_NEXT: // pagedown
case VK_PRIOR: // pageup
lhItem = GetFocusedItem();
if (IsSelected(lhItem))
{
CTreeCtrl::SetItemState(lhItem, 0, TVIS_SELECTED);
}
break;
Can anyone please help me in solving it
The Code need to written in OnSelChanging & OnSelChanged Event Handler functions
void CTreeCtrl::OnSelchanging(NMHDR *pNMHDR, LRESULT *pResult)
{
HTREEITEM hNew = pNMTreeView->itemNew.hItem;
HTREEITEM hOld = pNMTreeView->itemOld.hItem;
m_bOldItemSelected = hOld && (CTreeCtrl::GetItemState(hOld, UINT(TVIS_SELECTED)) & TVIS_SELECTED);
if (GetSelectedCount() > 1)
{
if (m_bPgUpState || m_bPgDownState)
{
//Check the state of New Item
if ((pNMTreeView->itemNew.state & TVIS_SELECTED))
{
// If the item is selected, so make sure OnSelchanged()
// will "select" it !
m_bNewItemSelected = TRUE;
}
else if (!(pNMTreeView->itemNew.state & TVIS_SELECTED))
{
// The New item is not selected, so make sure OnSelchanged()
// will not "re-select" it !
m_bNewItemSelected = FALSE;
CTreeCtrl::SetItemState(hNew, UINT(~TVIS_SELECTED), UINT(TVIS_SELECTED));
}
}
}
void TreeCtrl::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
HTREEITEM itemNew = pNMTreeView->itemNew.hItem;
HTREEITEM itemOld = pNMTreeView->itemOld.hItem;
if ((m_bPgUpState || m_bPgDownState) && (GetSelectedCount() > 1)
&& (pNMTreeView->itemOld.hItem != NULL || pNMTreeView->itemNew.hItem != NULL))
{
// It had the focus so Keep selection at old item
if (itemOld && m_bOldItemSelected)
{
CTreeCtrl::SetItemState(itemOld, UINT(TVIS_SELECTED), UINT(TVIS_SELECTED));
m_bOldItemSelected = FALSE;
}
else
{
// Do-not select the item if it is not selected
CTreeCtrl::SetItemState(itemOld, UINT(~TVIS_SELECTED), UINT(TVIS_SELECTED));
}
}
In this article you'll find solution for every thing about CTreeCtrl
Full-Featured Tree Control

Resources