Git Product home page Git Product logo

audio's People

Contributors

dy avatar greenkeeper[bot] avatar jamen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

audio's Issues

Things the core needs to include.

Things the code needs to include. I don't want to include lots of things, I just want some pretty universally helpful/common data stored here. Keep in mind things like codecs, speaker playback, compression, etc... variables domain-specific to those can remain as options to their modules.

Change writing to use iteration.

Iteration will be VERY helpful for writing multi-channel data.

For example, the use of generators would make it easy to write two dynamic channels at once:

const { PI, sin } = Math;

// Write sine waves
audio.write(function* (t, self) {
  // Channel 1 (first iteration)
  yield self.max * sin(2 * PI / 440 * t);

  // Channel 2 (second iteration)
  yield (self.max - 20) * sin(2 * PI / 1000 * 2);
});

With this, you could also use arrays to write static multi-channel data:

audio.write([12, 13]);

Then you could have single integers like 3 expand to [3, 3]

audio.write(3);
// Equivalent to
audio.write([3, 3]);

Issue in playback.js

I'm encountering "this._parseArgs is not a function" when calling audio.play

Is this a known issue? I do realize things are in flux at the moment. I can look into fixing it if you're looking for contributors. This project seems very promising.

Saved as [object ArrayBuffer]

My code is simply

const Audio = require('audio');

Audio.load('./test.mp3', (err, audio) => {
	//repeat slowed down fragment
	//audio.remove(3, 4.1)

	audio.save('edited-record.mp3')
})

and it causes the edited-record.mp3 to be just a text file with [object ArrayBuffer] as the contents. Node version is v10.15.3 on windows 10

Use typed arrays instead?

Since I'm trying to lay a pretty environment-agnostic foundation here for Audio, maybe I should consider using the TypedArray objects. That relies on the ECMAScript spec instead of Node's Buffer.

alternative audio data structures / storing ops instead of applying immediately

Following audiojs/audio-buffer-list#5.

The current API approach is covered by a lot of similar components, it is destined to insignificant competition and questionable value. The main blocker and drawback is the core - audio-buffer-list component, which does not bring a lot of value, compared to just storing linked audio-buffers.

Alternately, audio could be focused on storing editing-in-process, rather than data wrapper with linear API, similar to XRay RGA.

Principle

  • storing operations rather than applying them to data
    • πŸ‘ no precision loss
    • πŸ‘ faster insertion/removal
    • πŸ‘ allows for collaborative editing
    • πŸ‘ allows for faster re/adjusting params of applied control/envelope
    • πŸ‘Ž possibly somewhat slower playback due to applied transforms stack, hopefully having heavy-duty fx is not a part of editing process
      • ! possibly compiling fx program dynamically, akin to regl
      • ! pre-rendering audio for faster playback
  • undo/redo history methods store operations, not full binary replica every step
  • branching - allows for alternatives

Pros

  • πŸ‘ makes audio unique
  • πŸ‘ makes it suitable for editors

Create a blob from modified audio

Hi!
Is there any way to get a blob from modified audio?

Audio.decode(new Blob([someBlob]), (err, audio) => {
   const modified = audio.slice(0, 2.0);
   // here I want to get a Blob (e.x new Blob([modified]) or smth like this)
});

Streaming

The API draft is looking good, there is streaming issue.

  1. Should we provide partially loaded data, like HTMLMediaElement, or we work only with completely loaded buffer? I would opt for the second, because we can stream in later by audio.write(stream).
  2. audio.write(stream, offset) method can take streams as input, technically it can detect the type of stream. But how shoud we stream out? audio.read(offset, duration) returns buffer.
    1. Should we extend it to take type param so that audio.read(offset, duration, {type: 'stream'}) returns node stream, {type: 'function'} returns reader and {type: 'pull'}...
    2. Or we can pass {samplesPerFrame: 1024} which can return reader function, which can be used by stream later?
    3. We can provide audio.pull, audio.stream methods for according streams.

audio.channel

Property with raw channel data as

audio.channel[0]
audio.channel.L
audio.channel.SL

// but
audio.channels // audio.channel.length

Is there natural usability in that?

Make audio a wrapper over audio-buffer and audio-buffer-utils

Hi @jamen!
Do I understand right that audio is opinionated container for audio-data with some handy API methods? Is there any sense to pivot it from audio-buffer so to provide a bunch of common methods for audio manipulations, e. g. all from audio-buffer-utils?

That would be handy to require audio one time and have all the manip work done on some audio data, I could use that in wavearea as well.
Using audio-buffer and utils right now is a bit wearisome.

Enhancements

  • all API methods covered
  • logo
  • donate bitcoin badge
  • bitRate property
  • contribute section
  • revamped audiojs docs
  • cover aac, flac and alac codecs
  • use industry-standard samples (LINN records or 2l)
  • demo with editor
  • demo with visualizer and data
  • demo recorder/downloader
  • external data formats, like ndsamples, ndarray etc
  • full-featured playback module for node, probably related audiojs/audio-speaker#42
  • audio-load for integrating with various APIs
  • concise docs

Add support for writing single pulse values again.

Actually, it is useful to write single pulse values. When generating waveforms it is kind of annoying that I cannot write the pulses directly to the audio in the loop without initializing an array (ew slow).

Blob support

Hi, I tried blob but it seems that blob is not supported.
this:
(new Audio(blob,{length:blob.size}).remove(1,2);
throws:
Value must be an array or buffer.

Audio.stream() is not a function

I'm editing some audio files using Node 12.4 and this package... But at the moment to get the stream using Audio.stream() it shows me that isn't a function. Any solution?

Instructions omit how to get "require" to work

Edited (sorry for the confusion). The title of this query is wrong.

I tried to use your library with react-create-app and the method "load" is simply not found. It does find the library however when required. When I go into the module folder and look in the audio folder it looks like most of the library is missing. I feel like I am missing an install step

Anync vs sync API

We are facing presumably a problem of sync/async API here.

For example we create audio from remote url. What should happen if we instantly apply manipulations?

let audio = Audio(url);
audio.trim();
//is audio trimmed here? obviously not, as it is not loaded yet.
//should we plan it to be trimmed once it is loaded?
//or should we return error because we cannot trim not loaded data?

Planning reminds of jQuery pattern, where things get queued and applied in turn. The difference is that we aren’t (necessarily) bound to RT queue, therefore can do things at instant. Unless we expand Audio to a stream-of-chunks wrapper, which is a different story. Planning forces us to provide a callback for every manipulation method, which is bad for simple use and good for worker use.

1. Async way

jQuery/webworker classical async processing way.

let audio = Audio(url);
audio.trim().fadeIn(.5, (audio) => {
  //audio is trimmed/faded here
});
//here audio is not ready yet, but trim/fade are queued

βœ” enables webworker mode, freeing UI from heavy processing of large data
βœ” does not break natural workflow, the code style is sync but running of it is async
βœ” enables partially loaded data, like streams (potentially)
✘ makes workflow more difficult
✘ mb a tiny bit slower than sync way
✘ a bit unconventional API, considering possible promises style:

Audio(url)
  .then(a => a.trim())
  .then(a => a.fadeIn(.5))
  .then(a => a.download())

2. Sync way

This way is suggested in the zelgo article.

let audio = Audio(url);
audio.trim(); //throws error
audio.on('ready', () => {
  audio.trim().fadeIn(.5);
});

βœ” easy API
✘ blocking processing, esp. in case of large audio files

@jamen how do you think which one is better?

Fade in/out usability

Turns out that linear fading does not sound great. Seems that fist - some output devices have built-in limiter/compressor, second - loudness perception is not linear.

Should we tune fade so it not to be mathematically linear? audio-gain includes tangential mode of setting volume, should we do the same here? It thinks to me that having natural fade by default is preferable, and if one needs math fade one should use audio.process or audio.fill

Audio Playback Through Speakers

I'm currently working on a project to play a stream of audio back through the speakers. Can this be done using this project?

Audio.stream method.

Would be nice if there was a little utility to just create streams right out off the bat.

Audio.stream({ ...options })
.pipe(through2.obj(function(audio, enc, callback) {
  // ...
}));

Basic Example TypeError

When running the basic example I get a TypeError.

Code:

const Audio = require('audio')

Audio.load('./December.mp3').then(audio =>
  audio
    .trim()
    .normalize()
    .fade(.5)
    .fade(-.5)
    .save('sample-edited.wav')
).catch(err => { console.log(err); });

Output:

this.buffer.each is not a function
    at Audio.trim (/Users/…/node_modules/audio/src/manipulations.js:282:15)
    at Audio.load.then.audio (/Users/…/index.js:23:6)
    at <anonymous>

I tried using the npm version as well as npm i audiojs/audio, with .wav and .mp3. Any ideas?

npmjs 'audio' outdated?

on npmjs I find https://www.npmjs.com/package/audio listing 1.2.0 without any documentation.
on github, I find releases up to v2.0.0-1, but even those are from August 2016.

so I wonder if this project is still active and maintained...?

in fact, I'm looking for a way to change the speed of a PCM stream. my code looks like:

const lame    = require('lame');
const request = require('request');
const Speaker = require('speaker');

const decoder = new lame.Decoder();
const speaker = new Speaker({
  channels:   2,
  bitDepth:   16,
  sampleRate: 44100,
  mode:       lame.STEREO,
  device:     'hw:1,0',
});

const req = request.get(url);

req
  .pipe(decoder)
  .pipe(speaker);

and I wonder if I can make use of some part of audio to control the playback speed.

`unit` property

Possible cases

// string in options
audio.shift(100, 'ms')

// string args
audio.pad('2s')

// options param
audio.pad(2, {unit: 's'})

// predefine unit (bad, since different instances have different behavior)
audio = Audio(2, 's')
audio.pad(2)

Would that be demanded? Would that be better than audio.pad(audio.time(2))?

Error during npm install

During npm i audio I've got an error

> [email protected] install /home/yevhenii/Documents/node/audio-howler/node_modules/speaker
> node-gyp rebuild

make: Entering directory '/home/yevhenii/Documents/node/audio-howler/node_modules/speaker/build'
  CC(target) Release/obj.target/output/deps/mpg123/src/output/alsa.o
../deps/mpg123/src/output/alsa.c:19:28: fatal error: alsa/asoundlib.h: No such file or directory
compilation terminated.
deps/mpg123/output.target.mk:110: recipe for target 'Release/obj.target/output/deps/mpg123/src/output/alsa.o' failed
make: *** [Release/obj.target/output/deps/mpg123/src/output/alsa.o] Error 1
make: Leaving directory '/home/yevhenii/Documents/node/audio-howler/node_modules/speaker/build'

The purpose is to use audio in browser environment in Vue.js project

audio.read('left')

Is there any sense in channel naming convention to shorten args?

audio.write(data, 'left') //vs audio.write(data, {channel: 0})
audio.read('right') //vs audio.read({channel: 1})
audio.shift(-100, 'right') //vs audio.shift(audio.time(100), {channel: 1})
audio.channel[0]

.load is not a function

const audio = require('audio')

const newAudio = new audio()
newAudio.load('https://s3.amazonaws.com/philandrews/hardwell.mp3').then(audio => { 
    console.log(audio)
}, error => {
    console.log(error)
})

Error: newAudio.load is not a function

What am I missing here?

Clean up documentation.

I would like to rewrite documentation by hand. I don't really like how JSDoc does it.

  • Explain audio.js framework versus Audio.
  • Rewrite API documentation.
  • Rewrite utility documentation for stream API.
  • Add flowchart explaining source PCM format (blocks).
  • Add demos/examples.
  • Update README.

TypeError: saveAs is not a function

The error appeared using Audio library

Audio.load(link).then(audio =>
        audio
          .slice(this.range[0], (this.range[1] - this.range[0]), {copy: false})
          .save('sample-edited.mp3')
      )
Uncaught (in promise) TypeError: saveAs is not a function
    at eval (browser.js?f831:42)
    at new Promise (<anonymous>)
    at save (browser.js?f831:40)
    at Audio.save (core.js?a391:285)
    at eval (HelloWorld.vue?18db:122)

Audio was installed using npm i -S audiojs/audio

Async Iterable + diffs

Must implement async iterable interface to stream samples.

.slice must return ref to initial buffer, not immutable clone.
.trim and other modifiers must create diffs on the initial buffer, not change samples.

Audio.trim - API Priority

Great library!

Not sure if this is the right place for this but Audio.splice function would be fantastic to have access to. There is no other library for Node that has a splice functions. This whole library is novel against anything else available. Splicing would be big.

Is there a possible way to hack this using .trim method?

Recomposition / decluttering API

Current API comprises various concepts and various contexts, mixing them all up does not work well.
Let's try to analyze and clean them up, figure out the core value of the package, distinguished from just a heap of assorted audio aspects. On the way taking notes/ideas.

There are the following apparent contexts.

  • playback (stream to speaker)
  • recording (stream from mic)
  • manipulations
  • rendering & taking statistics (stream to analyzer)
  • reading & decoding (decode-stream from file)
  • saving & encoding (encode-stream to file)
  • generic streaming in (non-mic: web-audio, url, video/youtube, etc.)
  • generic streaming out (non-speaker: web-audio, renderer, generic observable/asyncIterator, icecast, p2p audio etc.)

Originally these concerns are handled each with separate node in audio-processing graph.
But they can be reclassified into:

  • create (from mic, file, buffer, encoded data, web-audio, url, video etc.)
  • read/output (to speaker, analyzer, buffer, encode, stream, observable, renderer, web-audio etc.)
  • manipulate (stack of string/array-like ops + audio-specific ops)
  • navigate (state of reading: seek, cues, skip, playback, rate, etc.)
  • sync/mix (video track, captions track, rendering? track, other tracks)

↑ With different flavors (type of data storage, time units convention, naming, stack of ops vs direct manipulations)

Also, it's worth correlating with MDN Audio - that includes own opinionated subset of operations.

Also, alternative audio modules (wad, aural, howler, ciseaux etc.) each has own subset of operations.

Consider possible concepts.

A. Audio (HTMLAudioElement) for node

! one possible value is to just provide standard Audio container for node.

  • πŸ‘ existing docs (MDN)
  • πŸ‘ compatible with web-audio-api pattern
  • πŸ‘Ž losing manipulations
  • πŸ‘Ž that implies implementing more generic Media class with a bunch of associates: AudioTrackList, AudioTrack, TimeRanges, MediaController, MediaError, MediaKeys, MediaDevices, MediaStream, TextTrack, VideoTrack, MediaKeySession - overall looks like an organic part of browser API, not some standalone polyfill.

B. Manipulations toolkit 🌟

  • simple decoded sync data container (AudioBuffer, Float32Array etc. - similar to pxls) - takes in any PCM/float data (likely audio-buffer-from).
  • for loading audio from remote source, use audio-load. For recording and other streaming sources - use corresp. packages.
  • basically extends AudioBuffer with a set of chainable methods (BTW! inherited AudioBuffer is compatible with regular one!)
    • ~ the possible drawback - audiobuffer is immutable - no easy way to trim/slice it etc.
    • ~ also for long (45s+) sources they recommend using MediaElementAudioSourceNode - which is a type of AudioNode.
  • for playing audio - use for example audio-play
  • πŸ‘ ↑ this way, the package can be focused on manipulations only without cramming all into one, and go a bit deeper, eg.

Benchmarking

Processing and creating audio fast is important, would be nice to do some benchmarks to test this.

Minimal duration of exported file

Turns out some players, like winapm, can't reproduce 1-sample wav.
Hence we may decide on whether we need force min-length file for save method.

Extend constructor to allow for async args

Similar to Image:

Audio('./x.wav', (err, a) => {})
Audio(blob).on('load', a => {})
Audio(file).then(a => {})
  1. That would allow to get rid of / hide .decode, .load methods.
  2. Audio w/o content loaded is in temporary state of empty buffer, but available already.
  3. That complicates Promise interface Audio(url).then(a => {}): audio is thenable.
  4. That mixes up sync/async pattern: some audio sources are available synchronously, like buffers, others only in async way.

Otherwise it is not clear the natural way of creating blobs: Audio.load(blob),Audio.decode(blob) or Audio.from(blob)?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.