Unable to mute one channel in wavesurfer.js - mute

I spent a few hours trying to select a single channel from a stereo mp3 file loaded with wavesurfer.js

I finally came up with a solution that's probably not the best, but It works with no problems.
The idea is to simply replace the buffer from the channel I want to mute with zeros. For that, I first store the original data with wavesurfer.backend.buffer.getChannelData(0), and create a zeros array with the same length. Then I replace the content of the channel by using wavesurfer.backend.buffer.copyToChannel(left_zeros, 0).
Works like a charm!
var wavesurfer = WaveSurfer.create({
container: '#waveform',
waveColor: 'darkorange',
progressColor: 'purple',
splitChannels: true,
height: 150,
});
left_data = null;
left_zeros = null;
right_data = null;
right_zeros = null;
wavesurfer.load('./stereo-file.mp3');
wavesurfer.on('ready', function () {
left_data = wavesurfer.backend.buffer.getChannelData(0).map(d => {
return d;
});
left_zeros = left_data.map(d => {
return 0.;
});
right_data = wavesurfer.backend.buffer.getChannelData(1).map(d => {
return d;
});
right_zeros = right_data.map(d => {
return 0.;
});
});
function playLeft() {
wavesurfer.backend.buffer.copyToChannel(left_zeros, 0);
wavesurfer.backend.buffer.copyToChannel(right_data, 1);
}
function playRight() {
wavesurfer.backend.buffer.copyToChannel(left_data, 0);
wavesurfer.backend.buffer.copyToChannel(right_zeros, 1);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/wavesurfer.js/1.2.3/wavesurfer.min.js"></script>
<div id="waveform"></div>
<p align="center">
<button class="btn btn-primary" onclick="playLeft()">
<i class="glyphicon glyphicon-play"></i>
Left
</button>
<button class="btn btn-primary" onclick="playRight()">
<i class="glyphicon glyphicon-play"></i>
Right
</button>
<button class="btn btn-primary" onclick="wavesurfer.playPause()">
<i class="glyphicon glyphicon-play"></i>
Play
</button>
</p>

export class PlayerComponent implements OnInit {
wavesurfer: WaveSurfer;
leftGain: any;
rightGain: any;
stateLeft: number = 1;
stateRight: number = 1;
constructor() { }
ngOnInit() {
let audiofile = '../assets/1.mp3';
this.wavesurfer = WaveSurfer.create({
container: '#waveform',
waveColor : 'blue',
progressColor: 'purple',
splitChannels: true,
responsive: true,
normalize: true
});
const splitter = this.wavesurfer.backend.ac.createChannelSplitter(2);
const merger = this.wavesurfer.backend.ac.createChannelMerger(2);
this.leftGain = this.wavesurfer.backend.ac.createGain();
this.rightGain = this.wavesurfer.backend.ac.createGain();
splitter.connect(this.leftGain, 0);
splitter.connect(this.rightGain, 1);
this.leftGain.connect(merger, 0, 0);
this.rightGain.connect(merger, 0, 1);
this.wavesurfer.backend.setFilters([splitter, this.leftGain, merger]);
this.wavesurfer.load(audiofile);
this.wavesurfer.on('play', () => {this.wavesurfer.playPause()});
this.wavesurfer.on('error', (msg) => {
console.log(msg);
});
}
play() {
this.wavesurfer.playPause();
}
right() {
if(this.stateRight == 1)
this.stateRight = 0;
else
this.stateRight = 1;
this.rightGain.gain.value = this.stateRight;
}
left()
{
if(this.stateLeft == 1)
this.stateLeft = 0;
else
this.stateLeft = 1;
this.leftGain.gain.value = this.stateLeft;
}
}
<div id="waveform"></div>
<button class="btn btn-success" (click)="play()">Play/Pause</button>
<button class="btn btn-success" (click)="left()">left</button>
<button class="btn btn-success" (click)="right()">right</button>

Related

FullCalendar Add Icon with myID

in the resources I would like to add an icon with an ID inside that I can pass on.
I tried with resourceLabelContent but it doesn't work for me
resourceGroupField: 'mygroup',
resourceColumns: [
{
labelText: 'Unità',
field: 'title',
},
{
labelText: 'Telefono',
field: 'Tel',
},
],
resources: {
url: 'fetch-resource.php',
method: 'POST',
},
resourceLabelContent: function (arg)
{
return { arg.resource.title + "'<i class="fas fa-users">'+arg.resource.myid+'</i>'"};
},
I solved it in part .... I modified the JS schduler so, in this way it puts the icons in the resources
ResourceRow.prototype.renderGutterHtml = function() {
var html, i, j, ref;
html = '';
for (i = j = 0, ref = this.depth; j < ref; i = j += 1) {
html += '<a href="#" class="far fa-envelope m-1 text-info sendMail"/></a>';
}
html += '<span class="fc-expander-space">' + '<a href="#" class="fas fa-chart-bar m-1 text-danger graphStat" color=red></a>' + '</span>';
return html;
};
then with "resourceRender" I go to assign the data-id, but then the click on the icon doesn't work
resourceRender: function(resource, cellEls) {
$('.graphStat').attr('data-id',resource.id);
$('.graphStat').on('click', function(e) {
alert($(this).data('id'));
});
},
what am I doing wrong

Reactjs, inline style with state data

I have mapped an array of words to the button group. and in the state I have an index and a color value
this.state = {
selectedWordIndex:'', //e.g. 3
selectedWordColor:'' //e.g. rgb(137,197,8)
}
the index and the color are set in another function.
var counter = -1;
return this.state.sentenceArray.map((word) => {
counter += 1
return (
<button
key={counter}
type="button"
className="btn btn-default"
style={{}}>{word}</button>);});
how can I change the color of the indexed button?
So if you want to change the color of button with the index === this.state. selectedWordIndex, following code should work.
var counter = -1;
return this.state.sentenceArray.map((word) => {
counter += 1
return (
<button
key={counter}
type="button"
className="btn btn-default"
style={ this.state.selectedWordIndex === counter ?
{ color:this.state.selectedWordColor } :
{}
}
>{word}</button>);});

On click a DIV apply dynamic data binding to edit the CSS using an HTML input - knockout.js

I'm trying to edit individual elements of an array.
I have a JSON array like this:
[ {"idComponent":1,"left":"100px","top":"100px","idHTML":"name_div","width":"200px","height":"300px","value":"My name is"}
,{"idComponent":2,"left":"200px","top":"200px","idHTML":"date_div","width":"200px","height":"300px","value":"2016-Enero-12"}
,{"idComponent":3,"left":"300px","top":"300px","idHTML":"weigth_div","width":"200px","height":"300px","value":"1.5 KG"}
,{"idComponent":4,"left":"400px","top":"400px","idHTML":"talla_div","width":"200px","height":"300px","value":"23"}
,{"idComponent":5,"left":"500px","top":"500px","idHTML":"description_div","width":"300px","height":"300px","value":"The text"}
]
These are converted to observables in knockout.
Each one is binded to a DIV element to display in screen.
"left", "top", "height" and "width" are CSS attributes that are applied to each one.
When you click ones of the DIV contains with the mouse, I'm trying to bind the element to HTML inputs to edit the CSS values. You can see the idea in the next picture:
Mockup Image - Click here to see the image
The code is the next:
function convertPixelsToInches(pixels){
return pixels/96;
}
// Elemento regresados desde el servidor.
var dataFromServer =
{
"idTemplate":"1"
,"components" :
[{"idComponent":1,"left":"100px","top":"100px","idHTML":"name_div","width":"200px","height":"300px","value":"Sergio Pinto Fernandez"}
,{"idComponent":2,"left":"200px","top":"200px","idHTML":"date_div","width":"200px","height":"300px","value":"2016-Enero-12"}
,{"idComponent":3,"left":"300px","top":"300px","idHTML":"weigth_div","width":"200px","height":"300px","value":"1.5 KG"}
,{"idComponent":4,"left":"400px","top":"400px","idHTML":"talla_div","width":"200px","height":"300px","value":"23"}
,{"idComponent":5,"left":"500px","top":"500px","idHTML":"description_div","width":"300px","height":"300px","value":"Tomar dos cucharadas cada 3 hras."}
]
,"paperSize":"papersize_USLetter_portrait"
,"templateImage":{
"imageUrl":"images/SolicitudLaboratorioExpress.jpg"
,"width":"8.5in"
,"height":"11in"
,"left":"0px"
,"top":"0px"
}
};
function componentModel(dataComponent) {
if (!dataComponent) {
dataComponent = {};
}
var self = this;
self.idComponent = ko.observable(dataComponent.idComponent);
self.left = ko.observable(dataComponent.left);
self.top = ko.observable(dataComponent.top);
self.idHTML = ko.observable(dataComponent.idHTML);
self.width = ko.observable(dataComponent.width);
self.height = ko.observable(dataComponent.height);
self.value = ko.observable(dataComponent.value);
}
/**
* data Json from server.
*
*/
function templateModel(data) {
if (!data) {
data = {};
}
var self = this;
self.components = ExtractComponents(self, data.components, componentModel);
self.currentSelectedComponent = ko.observable();
self.currentSelectedComponentIndex = ko.observable(-1);
//self.currentSelectedComponentLeft = ko.observable();
self.currentSelectedComponentLeft = ko.computed(function(){
var value = self.currentSelectedComponentIndex();
console.log(typeof value);
//value=value*1;
console.log(value);
if (value ) {
return "TT";
}
// Get "200px y must save as 200"
//return self.currentSelectedComponent().left;//.substring(0,data.length-2);
return "FF";
});
self.currentSelectedComponentTop = ko.observable();
self.editComponent = function(component,index){
self.currentSelectedComponentIndex(index);
self.currentSelectedComponent(component);
// Binding the component to the editor.
// ??
};
function bindComponentToEditor() {
ko.applyBindings()
}
self.idTemplate = ko.observable(data.idTemplate);
self.paperSize = ko.observable(data.paperSize);
/* */
self.paperSizeWidth = ko.observable(convertPixelsToInches(1067));
self.paperSizeHeigth = ko.observable(convertPixelsToInches(1067));
//
self.templateImage_imageUrl = ko.observable(data.templateImage.imageUrl);
self.templateImage_width = ko.observable(data.templateImage.width);
self.templateImage_height = ko.observable(data.templateImage.height);
self.templateImage_left = ko.observable(data.templateImage.left);
self.templateImage_top = ko.observable(data.templateImage.top);
}
/**
* parent: referencia al objeto o funcion que mando a llamar esta fucnion.
*
* dataArr: Array de elementos que se desea la funcion ExtractComponents haga mapeo.
* Ejemplo de dataArr:
*
* [ {"idComponent":1,"left":"100px","top":"100px","idHTML":"name_div","width":"200px","height":"300px","value":"Sergio Pinto Fernandez"}
,{"idComponent":2,"left":"200px","top":"200px","idHTML":"date_div","width":"200px","height":"300px","value":"2016-Enero-12"}
,{"idComponent":3,"left":"300px","top":"300px","idHTML":"weigth_div","width":"200px","height":"300px","value":"1.5 KG"}
,{"idComponent":4,"left":"400px","top":"400px","idHTML":"talla_div","width":"200px","height":"300px","value":"23"}
,{"idComponent":5,"left":"500px","top":"500px","idHTML":"description_div","width":"300px","height":"300px","value":"Tomar dos cucharadas cada 3 hras."}
]
*
* modelConstructor: funcion con que se creara un nuevo componente, es decir el modelo.
*
*/
function ExtractComponents(parent, dataArr, modelConstructor) {
var components = [];
if (dataArr == null) {
return components;
}
for (var i = 0; i < dataArr.length; i++) {
var dataArrElement = dataArr[i];
var component = new modelConstructor(dataArrElement,parent);
components.push(component);
}
return components;
}
ko.applyBindings(new templateModel(dataFromServer));
I have two problems:
The Input for left and top values only accept integer values, the i need substring "200px" to 200 but alway i receive a error: ".left is undefined"
self.currentSelectedComponentLeft = ko.computed(function(){
var value = self.currentSelectedComponentIndex();
console.log(typeof value);
//value=value*1;
console.log(value);
if (value ) {
return "TT";
}
// Get "200px and save as 200"
//return self.currentSelectedComponent().left;//.substring(0,data.length-2);
return "FF";
});
The principal problem... how can I bind the DIV element when I click the element to the inputs at the right?
I think I need dynamic binding, or dynamic subscription, but can't find answer to this problem of dynamic double data binding.
This is the HTML:
<div id="mainContainer">
<div id="contentPrint_div" class="page" data-bind="css: paperSize">
<img id="template_img" data-bind="attr: {src: templateImage_imageUrl},
style: {width: templateImage_width, height: templateImage_height, left: templateImage_left, top: templateImage_top}">
<div id="fieldsArea_div" class="" data-bind="foreach: components">
<div class="field" data-bind="html: value, style: {width: width, left:left, top:top},
attr: {id: idHTML}, click: $parent.editComponent($data,$index)"></div>
</div>
</div>
<div id="toolsbar">
<div id="toolbarPanel">
ID template:<span data-bind='text: idTemplate'></span>
<div id="panelMenuInfoElements_div">
Elemento actual: <span data-bind='text: idTemplate'></span>
Posicion
X:<input type="text" class="form-control" id="" placeholder="x" min="0" step="0.01"
data-bind="attr: {max: paperSizeWidth}, value: currentSelectedComponentTop">
Y:<input type="text" class="form-control" id="" placeholder="y" min="0" step="0.01"
data-bind="attr: {max: paperSizeHeigth}, value: currentSelectedComponentLeft">
</div>
</div>
<div id="toolbarCode">
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>
</div>
</div>
</div>
You posted quite some code; I'm not 100% sure if I got all your questions correctly. But I tried to create an example that I think shows how to solve your problems.
I've used a computed to create a style object that rewrites x and y observables that are numbers, to the style binding compatible: { top: 0px, left: 0px }
I've used a with binding to link your <input> elements to the last clicked block.
var Block = function(name, x, y) {
this.label = name;
this.x = ko.observable(x);
this.y = ko.observable(y);
this.style = ko.computed(function() {
return {
top: this.y() + "px",
left: this.x() + "px"
}
}, this);
}
var VM = function() {
this.blocks = [
new Block("Block 1", 100, 100),
new Block("Block 2", 200, 100),
new Block("Block 3", 300, 100),
];
this.selectedBlock = ko.observable(this.blocks[0]);
};
ko.applyBindings(new VM());
.Block {
position: absolute;
background: red;
padding: 1rem;
list-style: none;
}
.Block.is-selected { background: yellow; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="Inputs" data-bind="with: selectedBlock">
<div>
Editing <span data-bind="text: label"></span>
</div>
<div>Left:
<input type="number" data-bind="value: x">
</div>
<div>Top:
<input type="number" data-bind="value: y">
</div>
</div>
<ul data-bind="foreach: blocks">
<li class="Block" data-bind="
click: $parent.selectedBlock,
style: style,
text: label,
css: { 'is-selected': $data == $parent.selectedBlock()}"></li>
</ul>

How do I add input controls dynamically using Meteor?

I have a form in weather that would have had the condition User add as many lines he needs. He clicks a button and an input is added below the other.
I can do this using jQuery, but I would prefer to use the resources of Meteor. Is it possible to do?
Yes it is, here is an example from one of my apps using the underscore package
In the main template:
<template name="ask">
{{#each answerArray}}
{{>answer}}
{{/each}}
<button id="addItem">Add item</button>
</template>
<template name="answer">
<div class="input-group pt10">
<input class="form-control answer" maxlength="30" placeholder="Answer (max 30 chars)" name="answer" />
<span class="input-group-btn">
<button class="btn btn-danger delButton" id="{{id}}" data-id="{{id}}" type="button">Delete</button>
</span>
</div>
</template>
In the js file:
Template.ask.created = function () {
Session.set('action', 'ask');
answerArray = [ //adding at least two items but it could also be empty
{
id: Random.id(), //using this to give an unique id to the control
value: ''
},
{
id: Random.id(),
value: ''
}
];
Session.set('answerArr', answerArray);
}
And the click event:
Template.ask.events = {
'click #addItem': function () {
var answerArray = Session.get('answerArr');
answerArray.push({
id: Random.id() //just a placeholder, you could put any here
});
Session.set('answerArr', answerArray);
}
}
And finally the helper:
Template.ask.helpers({
answerArray: function () {
var answerArray = Session.get("answerArr")
while (answerArray.length < 2) { //i chose to have it between 2 and 6, you can remove these
answerArray.push({
id: Random.id()
})
}
while (answerArray.length > 6) { // maximum
answerArray.pop();
}
Session.set('answerArr', answerArray);
return answerArray;
}
}
This will reactively increase the number of inputs. After that, if you want to process the inputs you could do the following, on a submit form event or button click:
'click #saveQ': function (e) {
e.preventDefault();
var arr = [];
_.each($('.answer'), function (item) {
if ($(item).val() != '')
arr.push({
answer: $(item).val(), //this you customize for your own purposes
number: 0
})
});
And also if you want to delete an input from the page you can use:
Template.answer.events = {
'click .delButton': function (e) {
var thisId = $(e.target).attr("id");
var answerArray = Session.get('answerArr');
var filteredArray = _.filter(answerArray, function (item) {
return item.id != thisId;
});
Session.set('answerArr', filteredArray);
}
}

Knockout js: Add Class to each nth item

Is there any simple way to do something like jquery i.e.
$('#image-gallery li:nth-child(3)').addClass('third-image-child')
but in the context of knockout, I am completely new to knockout but can't seem to find a simple way of doing something which seems like it should be so simple? I thought it might be something to do with finding the 3rd item in the observable array and adding the class but am not sure of the syntax. Help??!
My model is below, it is a simple pagination model, that loads 9 items, and then has next and previous buttons. For now I have added a simple function to generate 100 items just to test it out.
members.DisplayGallery = function(jsondata) {
var viewModel = {
fields: ko.observableArray(jsondata),
pageSize: ko.observable(9),
pageIndex: ko.observable(0),
previousPage: function() {
this.pageIndex(this.pageIndex() - 1);
},
nextPage: function() {
this.pageIndex(this.pageIndex() + 1);
}
};
viewModel.maxPageIndex = ko.dependentObservable(function() {
return Math.ceil(this.fields().length / this.pageSize()) - 1;
}, viewModel);
viewModel.pagedImages = ko.dependentObservable(function() {
var size = this.pageSize();
var start = this.pageIndex() * size;
return this.fields.slice(start, start + size);
}, viewModel);
ko.applyBindings(viewModel, $('#image-gallery')[0]);
};
$(function() {
var data = [];
for (var i = 0; i < 100; i++) {
data.push({
imageLink: "http://sample-image.jpg",
imagePageLink: "http://",
imageTitle: "Title here" + i,
userFullName: "Name" + i,
imageDate: "Description" + i
})
}
members.DisplayGallery(data);
});
Markup:
<ul data-bind="foreach: pagedImages" id="image-gallery">
<li>
<div class="image-thumb" data-bind="style: { backgroundImage: 'url(' + imageLink +')'}">
<a class="image-thumb-link" data-bind="attr: { href: imagePageLink}" href="gallery-single.html"></a>
</div>
<div class="image-text">
<a data-bind="attr: { href: imagePageLink}" href="gallery-single.html"><span class="image-title" data-bind="text: imageTitle"></span></a><br />
<span data-bind="text: userFullName">Username</span><br />
<span data-bind="text: imageDate">Image Date</span>
</div>
</li>
</ul>
If you bind to your observable array using the foreach binding, you can use the $index context property to set the class of every 3rd element, like so:
<li data-bind="css: { 'third-image-child': $index() % 3 == 0 }">
...
</li>

Resources