Cut and Paste audio using web audio api and wavesurfer.js - javascript

I am currently trying to make a web editor allowing users to easily adjust basic settings to their audio files, as a plugin I've integrated wavesurfer.js as it has a very neat and cross-browser solution for it's waveform.
After indexing a must-have list for the functionalities I've decided that the cut and paste are essential for making this product work, however after spending hours of trying to figure out how to implement this in the existing library and even starting to rebuild the wavesurfer.js functionalities from scratch to understand the logic I have yet to succeed.
My question would be if anyone can give me some pointers on how to start building a cut and paste functionality or maybe even an example that would be greatly appreciated.
Thanks in advance!
wavesurfer plugin:
http://wavesurfer-js.org
plucked web editor
http://plucked.de
EDIT Solution (instance is the wavesurfer object.):
function cut(instance){
var selection = instance.getSelection();
if(selection){
var original_buffer = instance.backend.buffer;
var new_buffer = instance.backend.ac.createBuffer(original_buffer.numberOfChannels, original_buffer.length, original_buffer.sampleRate);
var first_list_index = (selection.startPosition * original_buffer.sampleRate);
var second_list_index = (selection.endPosition * original_buffer.sampleRate);
var second_list_mem_alloc = (original_buffer.length - (selection.endPosition * original_buffer.sampleRate));
var new_list = new Float32Array( parseInt( first_list_index ));
var second_list = new Float32Array( parseInt( second_list_mem_alloc ));
var combined = new Float32Array( original_buffer.length );
original_buffer.copyFromChannel(new_list, 0);
original_buffer.copyFromChannel(second_list, 0, second_list_index)
combined.set(new_list)
combined.set(second_list, first_list_index)
new_buffer.copyToChannel(combined, 0);
instance.loadDecodedBuffer(new_buffer);
}else{
console.log('did not find selection')
}
}

Reading this answer suggests you can create an empty AudioBuffer of the size of the audio segment you want to copy (size = length in seconds ⨉ sample rate), then fill its channel data with the data from the segment.
So the code might be like this:
var originalBuffer = wavesurfer.backend.buffer;
var emptySegment = wavesurfer.backend.ac.createBuffer(
originalBuffer.numberOfChannels,
segmentDuration * originalBuffer.sampleRate,
originalBuffer.sampleRate
);
for (var i = 0; i < originalBuffer.numberOfChannels; i++) {
var chanData = originalBuffer.getChannelData(i);
var segmentChanData = emptySegment.getChannelData(i);
for (var j = 0, len = chanData.length; j < len; j++) {
segmentChanData[j] = chanData[j];
}
}
emptySegment; // Here you go!
// Not empty anymore, contains a copy of the segment!

Interesting question. First word that comes to mind is ffmpeg. I can't talk from experience but if I was trying to achieve this I would approach it like:
Let's assume you select a region of your audio track and you want to copy it and make a new track out of it (later maybe just appending it to an existing track).
Use the getSelection() method provided by the nice wavesurfer.js library. This will give you startPosition() and endPosition()[in seconds].
Given those points you now can use ffmpeg on the backend to select the region and save it as a new file (eventually upload it to S3,etc.). See this thread to get an idea of how to call ffmpeg from your ruby app (the commandline parameters shown there can be helpful too).
Note that if you plan to copy and paste many regions to piece up a new track, making this in the backend all the time will probably make no sense, and I guess I'd try to look for a client-side JS approach.
I hope this is helpful at least for an easy use case, and gets you started for the rest ;)
Update
This might be worth reading.
Web Audio API, tutorial here.
HTML5 audio - State of play. here(don't miss the section on TimeRanges, looks like a reasonable option to try).
This one(Outdated, but worth a look, interesting links).

Related

Read data from excel to database in sailsjs

Recently, I try to learn sails.js. Thus I learn it through google and internet, and sails.js is still new, I encountered some trouble while finding any example of reading data from excel (*.xls and *.xlsx files). Can anyone show me how? On google, I found xlsx module (install by npm install xlsx ) but I still dont know what I have to write in controller and in view files. Thank you a lot!
xlsx will permit you to read a file at the server level, but you're going to have to work on the code to get that data into your views. I can't tell if you're trying to upload files and then read them or just read a static file. At any rate I hope that this is a start as it surely isn't a comprehensive solution.
Here is some example code from one of my scripts that goes down the rows and gets some info from some cells.
var XLSX = require('xlsx'),
xls_utils = XLSX.utils;
var workbook = XLSX.readFile('./file.xls');
var num_rows = xls_utils.decode_range(sheet['!ref']).e.r;
var sheet = workbook.Sheets[workbook.SheetNames[0]];
for(var i = 0, l = num_rows; i < l; i++){
// Get cell in {c}olumn 2 (0=1 like arrays) and {r}ow: i
var cell = xls_utils.encode_cell({c:1, r:i});
var value = sheet[cell];
// Do something with value here
}
You can do a lot more with it and you'll have to play around with it. I find the documentation to be a little rough to get through but the info is all there.

Paper.js Server-Side Can't Work with Received Layers

In an effort to reduce clientside load, we are attempting to do the work of flattening Paper.js layers on a Node Express server. We have many layers to flatten with lots of image data. And rather than overwriting our data structure, we want to end up with new objects containing the rasterized (flattened) layers.
So we have an Express route that looks like this:
app.post('/flatten', function (request, response) {
var pdfs = JSON.parse(request.body.pdfs);
// Attempt to set up canvas on the server side to work with
var canvas = new paper.Canvas(1000, 1000);
paper.setup(canvas);
paper.view.draw();
for (var i = 0; i < pdfs.length; i++) {
var pdf = pdfs[i];
if (pdf !== null) {
for (var j = 0; j < pdf.pages.length; j++) {
if (pdf.pages[j].layer !== undefined) {
paper.project.layers.push(pdf.pages[j].layer); // Attempt to add to current project; necessary?
pdf.pages[j].layer.activate(); // Blows up
pdf.pages[j].layer.visible = true;
var layerAsRaster = pdf.pages[j].layer.rasterize(); // Blows up
layerAsRaster.visible = false;
var dataString = layerAsRaster.toDataURL();
pdfs[i].pages[j].pageImageData = dataString.split(',')[1];
pdf.pages[j].layer.visible = false;
}
}
}
}
response.send(pdfs);
});
The .layer is a native Paper.js layer that was made on the clientside.
We receive this error when hitting this route:
TypeError: pdf.pages[j].layer.activate is not a function
Thinking that perhaps we don't need to worry about activating layers on the serverside, I commented that out, but got the same error for the .rasterize line. (See the two lines commented "Blows up".)
Do I need to somehow import the layers we're receiving from the client into the project? I attempt to do that with the line:
paper.project.layers.push(pdf.pages[j].layer);
but to no avail.
How can I modify this method to successfully work with layers on the serverside?
The problem is that you are directly adding the layer to the project with the line paper.project.layers.push(pdf.pages[j].layer);
You're not allowed to directly manipulate paper's data structures. If you want to add a layer to a project use the following (note that this is not documented and will change with the next release of paper, but I don't think you'll need to do this):
(paperscript)
project.addChild(layer);
(javascript)
paper.project.addChild(layer);
It's not clear how pdf.pages[i].layer was created on the server side, whether it was imported via JSON (in which case it could already be inserted into the project), or whether it was removed from another project, so there may be other complications.
I think there is another problem. It doesn't appear that pdf.pages[i].layer has been turned into a server-side layer. So the key question is how was it transferred from the client to the server?
Here's a stab at the whole process:
(client side)
jsonLayer = paper.project.activeLayer.exportJSON();
// send jsonLayer to server using some method
(server side)
// get jsonLayer from client
layer = new paper.Layer();
layer.importJSON(jsonLayer);
layer should already be inserted into the project and should contain all the items that were in jsonLayer which was the layer on the client.
Here's a link to a discussion on how importJSON and exportJSON map to one another:
paperjs group discussion

Photoshop Scripting: iterating list of all layers withing the layerset is very slow

The task that I'm trying to implement is very simple:
I need to get a list of all layers (one-level), within a specified layer set (group), and to write this list to a file.
The code is simple (and working) as well:
function indexCurrent(document){
var log = new File(indexLocation+document.name+'.js');
alert("Collecting data");
var images = document.layerSets.getByName("Images").layers;
var imagesLength = images.length;
var layers = [];
alert("Iterating " + imagesLength + " layers");
for(var jj = 0, jL = imagesLength; jj < jL; jj++){
layers.push('\t\t\'' + images[jj].name + '\'');
}
alert("Writing " + layers.length + " layers");
log.open('w');
log.write('\n\t\'' + document.name + '\': [\n' );
log.write(layers.join(",\n"));
log.write('\n\t]\n');
log.close();
}
This code works, but for 150+ layers it takes hours between "Iterating" and "Writing" lines.
I have read all related questions here, but that doesn't help.
I'm sure that there should be much more efficient way for such a simple task.
I'm running Photoshop CS6 on Windows 7.
Thanks.
I suggest you try switching from accessing the layers via the DOM to getting at them via the action manager. I'm pretty sure you'll get better performance that way. I'm terrible with the action manager code so I can't give you a working example - just something to google :)
Runs fine and fast for me, but you didn't state how large the source psd is.
Anyhoo, have a look here:
Action Manager layer search
I can't run it as I'm running good old CS2. Ye-har!

Box2d javascript add images to bodies and manage art assets

OK so I have a few levels of a simple platform built out,
so I just need some insight on how to assign images to bodies, and handle images, etc. The game is a simple platform game, with a ball as the palyer chacter and
you have to try to reach the other side. I have some obstacles like
joints and swinging balls, etc. Just getting it started, please let
me know if you can help... box2dweb.. Here is an example of a few
bodies inside my game in various places.. Any advice would be greatly
appreciated. Pplayer character let me know if you can help.
function PC(gamePiece){
if (gamePiece == 1) {
var ballSd1 = new b2CircleDef();
ballSd1.density = 1.1;
ballSd1.radius = 22;
ballSd1.restitution = 0.5;
ballSd1.friction = 1;
ballSd1.userData = 'player';
var ballBd = new b2BodyDef();
ballBd.linearDamping = .03;
ballBd.allowSleep = false;
ballBd.AddShape(ballSd1);
ballBd.position.Set(40,0);
player.object = world.CreateBody(ballBd);
}
ok so i am using box2d and need some help adding images to bodies...
I guess you do not generate your world programmatically. You will need to find an editor suitable for this job, or write one yourself.
I can advice you to use R.U.B.E which lets you create your Box2D worlds and attach images to the bodies. You may then export the scene via JSON which fits very well to javascript.
The rendering of those images attached to bodies will be a custom job. As well as the importing of the scene if there is no loader for box2dweb yet.

getting pictures into an array in javascript

im kinda new to javascript i mean i know the syntax but not so much the libraries.
i need some help to get some files (pictures) from a folder into an arry lets say:
var[] pictures = ?;
(the folder is in my project and contain some pictures)
so i can loop over them and diplay them on the page i did some search but i didnt find any guide on how to do this.
i realy want to understand on how to do this for future projects even a link to known guid you guys know we will be a big help.
if it help im using asp.net.
Well, there are a lot of ways to approach the problem, to me what you can do is (if you don't know the location of the images beforehand) make a service that returns the src of every image, store that in an array, and then show them in the page.
I believe you are using jQuery so you can make an ajax request like this:
jQuery.ajax({
url: /*path to*/"Service.asmx/getSources"
//options, check documentation
});
then, from asp, make a new service (Service.asmx in my case) and create a method that returns the location of the pictures (in my case the method is called getSources)
I recommend you use JSON (and jQuery.getJSON() method) so you can return a List<string>.
Lastly you can iterate or store the sources in an array, I'll put an example with the getJSON method
var sources = []
jQuery.getJSON("Service.asmx/getSources", function(data) {
for(var i = 0, len = data.length; i<len ; i++) {
sources.push(data[i]);//store every source in the array
}
});
once you have the sources you can display them like this fiddle
Tell me if it helped or if you need another solution.
If you want an array of pictures just to display them later, you can simply use:
var sources = [
"path/to/yourImage1.jpg",
"path/to/yourImage2.jpg",
// ...
"path/to/yourImageN.jpg",
];
var pics = [];
for(var i = 0; i < sources.length; i++) {
var pic = new Image();
pic.src = sources[i];
pics[i] = pic;
}

Categories

Resources