smoooty / ciseaux

JavaScript utility to chop an audio buffer

Home Page:http://mohayonao.github.io/ciseaux/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ciseaux

Build Status NPM Version Coverage Status License

JavaScript utility to chop an audio buffer, inspired from youpy/scissor

✂️ Demo

✂️ Documents

✂️ Installation

$ npm install ciseaux

downloads:

✂️ API

  • Ciseaux.context = AudioContext
  • Ciseaux.from(src: string): Promise<Tape>
  • Ciseaux.silence(duration: number): Tape
  • Ciseaux.concat(...tapes: Tape): Tape
  • Ciseaux.mix(...tapes: Tape, [method='silence']): Tape

Instance attributes

  • sampleRate: number readonly
  • length: number readonly
  • duration: number readonly
  • numberOfChannels readonly
  • numberOfTracks readonly

Instance methods

  • gain(gain: number = 1): Tape
  • pan(pan: number = 0): Tape
  • reverse(): Tape
  • pitch(rate: number = 1): Tape
  • stretch(rate: number = 1): Tape
    • not implemented (Pull Request please)
  • concat(...tapes: Tape): Tape
  • slice(startTime: number = 0, duration: number = inf): Tape
  • loop(n: number = 2): Tape
  • fill(duration: number): Tape
  • replace(startTime: number = 0, duration: number = 0, tape: Tape = null): Tape
  • split(n: number = 2): Tape[]
  • mix(...tapes: Tape, [method = 'silence']): Tape
  • render(): Promise<AudioBuffer>
  • dispose(): void

Ciseaux.Sequence

Utility class for creating a sequence tape that is concatenated tapes

  • constructor(...args: any)
    • pattern: string
    • durationPerStep: number|number[]
    • instruments: object

Instance methods

  • apply(...args: any): Tape
    • pattern: string
    • durationPerStep: number|number[]
    • instruments: object

✂️ Usage

browser

const Ciseaux = require("ciseaux/browser");

Ciseaux.context = new AudioContext();

// create a tape instance from the url
Ciseaux.from("/path/to/audio.wav").then((tape) => {
  // edit tape
  tape = Ciseaux.concat([ tape.slice(10, 1), tape.slice(2, 3) ]).loop(4);

  // render the tape to an AudioBuffer
  return tape.render();
}).then((audioBuffer) => {
  play(audioBuffer);
});

node.js

const fs = require("fs");
const Ciseaux = require("ciseaux/node");

// create a tape instance from the filepath
Ciseaux.from("/path/to/audio.wav").then((tape) => {
  // edit tape
  tape = Ciseaux.concat([ tape.slice(10, 1), tape.slice(2, 3) ]).loop(4);

  // render the tape to Buffer (wav format)
  return tape.render();
}).then((buffer) => {
  fs.writeFile("/path/to/ciseauxed.wav", buffer);
});

✂️ Examples

slice + concat

tape = tape2.slice(0, 1.5).concat(
  tape3.slice(0, 0.5), tape1.slice(-2)
);

slice + concat + loop

tape = tape3.slice(0, 0.5).concat(
  Ciseaux.silence(0.5)
).loop(4);

replace + reverse

tape = tape1.replace(2, 3, function(tape) {
  return tape.reverse();
});

gain

tape = Ciseaux.concat(
  tape1.split(25).map(function(tape, i) {
    return tape.gain(i / 25);
  })
);

pan

tape = Ciseaux.concat(
  tape1.split(25).map(function(tape, i) {
    return tape.pan(i % 2 ? -0.85 : +0.85);
  })
);

pitch

tape = Ciseaux.concat(
  tape1.split(25).map(function(tape, i) {
    return tape.pitch(i / 50 + 0.75);
  })
);

mix

tape = tape1.mix(tape2.gain(0.5), "fill").fill(30);

stutter

tape = Ciseaux.concat(
  tape2.split(16).map(function(tape) {
    return tape.loop(4).pitch(1.5);
  })
).fill(30);

phase

tape = Ciseaux.mix(
  [ 1, 0.95 ].map(function(rate) {
    return tape2.pitch(rate).fill(30);
  })
);

lace

tape = Ciseaux.concat(tape1.split(32).map(function(tape, index) {
  return index % 2 ? tape2.pitch(2).fill(tape.duration) : tape;
})).fill(30);

concrete

tape = Ciseaux.mix([ -12, -10, -7, -3, 0 ].map(function(midi) {
  return tape1.pitch(Math.pow(2, midi * 1/12));
}), "fill").gain(0.5).fill(30);

sequence

tape = new Ciseaux.Sequence("a bdacbba babfeg", 0.2, {
  a: tape1.split(16)[0],
  b: tape1.split(16)[1],
  c: tape1.split(16)[2],
  d: tape1.split(16)[3].gain(0.15),
  e: tape2.split(16)[4].pitch(0.25),
  f: tape2.split(16)[5].pitch(4).gain(0.1),
  g: tape3.pitch(32),
}).apply().fill(30);

shuffled sequence

tape = new Ciseaux.Sequence("a bdaabcaccbgabb", {
  a: tape1.split(16)[4],
  b: tape1.split(16)[1],
  c: tape1.split(16)[2],
  d: tape1.split(16)[3].gain(0.15),
  e: tape2.split(16)[4].pitch(0.25),
  f: tape2.split(16)[5].pitch(4).gain(0.1),
  g: tape3.pitch(32),
}).apply([ 2/3, 1/3 ].map(function(x) { return x * 0.3; })).fill(30);

✂️ Architecture

+---------------+     +----------------+                +-----------+
| new Tape()    | --> | Float32Array[] | -- transfer -> |           |
|               |     +----------------+                |           |
|               |                                       |           |
|               |     +----------------+                |           |
| Tape.render() | --> | JSON           | -- transfer -> | WebWorker |
+---------------+     +----------------+                |           |
                                                        |           |
+---------------+     +----------------+                |           |
| AudioData     | <-- | Float32Array[] | <- transfer -- |           |
+---------------+     +----------------+                +-----------+
  |
  +----------------+
  | browser        | node.js
  v                v
+-------------+  +---------------------+
| AudioBuffer |  | Buffer (wav format) |
+-------------+  +---------------------+

✂️ Developments

# Build : babel -> browserify -> uglify-js
npm run build

# Test : mocha + power-assert
npm run test

# Coverage : mocha + isparta
npm run cover

# Lint : eslint
npm run lint

✂️ Contributing

  1. Fork it!
  2. Create your feature branch: git checkout -b my-new-feature
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request :D

✂️ License

MIT

About

JavaScript utility to chop an audio buffer

http://mohayonao.github.io/ciseaux/


Languages

Language:JavaScript 94.7%Language:HTML 5.3%