├── test.html
├── test.js
├── package.json
├── .gitignore
├── index.js
└── readme.md
/test.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | var Render = require('./');
2 | var Generator = require('audio-generator');
3 | var Sink = require('stream-sink');
4 | var Canvas = require('drawille-canvas');
5 | var isBrowser = require('is-browser');
6 |
7 | var canvas = new Canvas(120, 80);
8 |
9 | Generator().pipe(Render({
10 | channel: 0,
11 | canvas: canvas,
12 | render: function (canvas) {
13 | var data = this.getTimeData();
14 |
15 | var ctx = canvas.getContext('2d');
16 |
17 | ctx.clearRect(0,0,canvas.width, canvas.height);
18 |
19 | if (!data.length) return;
20 |
21 | //get average magnitude
22 | var w = 5;
23 | var magnitude = 0;
24 | for (var i = 1; i <= w; i++) {
25 | magnitude += data[data.length - i];
26 | }
27 |
28 | magnitude /= w;
29 | magnitude = magnitude / 2 + 0.5;
30 |
31 | ctx.fillRect(0,0, magnitude * canvas.width, 20);
32 | ctx.fillText('Magnitude: ' + magnitude, 0, 40);
33 |
34 | }
35 | }))
36 | .on('render', function (canvas) {
37 | if (!isBrowser) {
38 | process.stdout.write(canvas._canvas.frame());
39 | }
40 | })
41 | .pipe(Sink());
42 |
43 | if (isBrowser) {
44 | document.documentElement.appendChild(canvas);
45 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "audio-render",
3 | "version": "2.0.1",
4 | "description": "Class for rendering audio stream data for frequency/time domains. Browser/node.",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "node test",
8 | "watch": "watchify ./test.js -d -o ./bundle.js"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/audio-lab/render"
13 | },
14 | "keywords": [
15 | "audio",
16 | "pcm",
17 | "stream",
18 | "render",
19 | "canvas",
20 | "drawille",
21 | "sound",
22 | "spectrum",
23 | "spectrogram",
24 | "waveform",
25 | "frequency",
26 | "fft",
27 | "stft"
28 | ],
29 | "author": "Deema Yvanow ",
30 | "license": "MIT",
31 | "bugs": {
32 | "url": "https://github.com/audio-lab/render/issues"
33 | },
34 | "homepage": "https://github.com/audio-lab/render",
35 | "dependencies": {
36 | "audio-analyser": "^1.0.1",
37 | "drawille-canvas": "^1.0.0",
38 | "inherits": "^2.0.1",
39 | "is-browser": "^2.0.1"
40 | },
41 | "devDependencies": {
42 | "audio-generator": "^1.0.5",
43 | "stream-sink": "^1.2.0",
44 | "watchify": "^3.6.0"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | //this will affect all the git repos
2 | git config --global core.excludesfile ~/.gitignore
3 |
4 |
5 | //update files since .ignore won't if already tracked
6 | git rm --cached
7 |
8 | # Compiled source #
9 | ###################
10 | *.com
11 | *.class
12 | *.dll
13 | *.exe
14 | *.o
15 | *.so
16 |
17 | # Packages #
18 | ############
19 | # it's better to unpack these files and commit the raw source
20 | # git has its own built in compression methods
21 | *.7z
22 | *.dmg
23 | *.gz
24 | *.iso
25 | *.jar
26 | *.rar
27 | *.tar
28 | *.zip
29 |
30 | # Logs and databases #
31 | ######################
32 | *.log
33 | *.sql
34 | *.sqlite
35 |
36 | # OS generated files #
37 | ######################
38 | .DS_Store
39 | .DS_Store?
40 | ._*
41 | .Spotlight-V100
42 | .Trashes
43 | # Icon?
44 | ehthumbs.db
45 | Thumbs.db
46 | .cache
47 | .project
48 | .settings
49 | .tmproj
50 | *.esproj
51 | nbproject
52 |
53 | # Numerous always-ignore extensions #
54 | #####################################
55 | *.diff
56 | *.err
57 | *.orig
58 | *.rej
59 | *.swn
60 | *.swo
61 | *.swp
62 | *.vi
63 | *~
64 | *.sass-cache
65 | *.grunt
66 | *.tmp
67 |
68 | # Dreamweaver added files #
69 | ###########################
70 | _notes
71 | dwsync.xml
72 |
73 | # Komodo #
74 | ###########################
75 | *.komodoproject
76 | .komodotools
77 |
78 | # Node #
79 | #####################
80 | node_modules
81 |
82 | # Bower #
83 | #####################
84 | bower_components
85 |
86 | # Folders to ignore #
87 | #####################
88 | .hg
89 | .svn
90 | .CVS
91 | intermediate
92 | publish
93 | .idea
94 | .graphics
95 | _test
96 | _archive
97 | uploads
98 | tmp
99 |
100 | # Vim files to ignore #
101 | #######################
102 | .VimballRecord
103 | .netrwhist
104 |
105 | bundle.*
106 |
107 | _demo
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Rendering stream.
3 | *
4 | * It does not transform audio to text
5 | * because rendering may require repetition of the same data multiple times.
6 | * It just plots captured amount of data to a canvas in user-defined way.
7 | *
8 | * Separation by node/browser files is also unnecessary,
9 | * we can detect environment in-place without serious size overdraft.
10 | * All the required modules provide short browser versions.
11 | *
12 | * Any routines which may vary, like sliding window behaviour,
13 | * realtime data binding, etc are left to user.
14 | *
15 | * It is a transform stream with exception where there are no piped outputs,
16 | * it releases data, i. e. behaves like a writable.
17 | *
18 | * @module audio-render
19 | */
20 |
21 |
22 | var inherits = require('inherits');
23 | var Analyser = require('audio-analyser');
24 | var isBrowser = require('is-browser');
25 | var Canvas = require('drawille-canvas');
26 |
27 |
28 | //detect rendering scheduler
29 | var raf, cancel;
30 | if (isBrowser && (raf = requestAnimationFrame)) {
31 | cancel = cancelAnimationFrame;
32 | }
33 | else {
34 | raf = setTimeout;
35 | cancel = clearTimeout;
36 | }
37 |
38 |
39 | /**
40 | * @constructor
41 | */
42 | function RenderStream (options) {
43 | if (!(this instanceof RenderStream)) return new RenderStream(options);
44 |
45 | var self = this;
46 |
47 | if (options instanceof Function) {
48 | options = {
49 | render: options
50 | };
51 | }
52 |
53 | Analyser.call(self, options);
54 |
55 |
56 | //ensure canvas
57 | if (!self.canvas) {
58 | self.canvas = new Canvas();
59 | }
60 |
61 | //set throttling
62 | self.throttle = 1000 / self.framesPerSecond;
63 |
64 |
65 | //plan rendering
66 | self._id = raf(update, self.throttle);
67 |
68 | //stop on end
69 | self.on('end', function () {
70 | cancel(self._id);
71 | });
72 |
73 | function update () {
74 | self._id = raf(update, self.throttle);
75 |
76 | try {
77 | self.render(self.canvas, self._data);
78 | } catch (e) {
79 | throw e;
80 | }
81 |
82 | try {
83 | self.emit('render', self.canvas);
84 | } catch (e) {
85 | throw e;
86 | }
87 | }
88 | }
89 |
90 |
91 | /** It should be duplex not to block pipe if there is no output sink */
92 | inherits(RenderStream, Analyser);
93 |
94 |
95 |
96 | /** How often to update */
97 | RenderStream.prototype.framesPerSecond = 20;
98 |
99 |
100 | /**
101 | * Default rendering method, does nothing
102 | * @override
103 | */
104 | RenderStream.prototype.render = function (canvas, data) {
105 |
106 | };
107 |
108 |
109 | module.exports = RenderStream;
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | _Audio-render_ is a pass-through audio stream, providing structure for rendering stream audio data.
2 |
3 | It resolves common routines like frequency analysis (fft), buffering data, reading pcm format, providing unified API for rendering both in node/browser, events, options, hooks etc. Creating new rendering components based on _audio-render_ is as simple as creating them from scratch, but times more reliable. It is also useful for creating quick debuggers.
4 |
5 |
6 | ## Usage
7 |
8 | [](http://npmjs.org/package/audio-render)
9 |
10 | ```js
11 | myAudioStream
12 | .pipe(Render(function (canvas) {
13 | var data = this.getFloatTimeDomainData();
14 |
15 | //draw volume, spectrum, spectrogram, waveform — any data you need
16 | }))
17 | .pipe(Speaker());
18 | ```
19 |
20 | ## API
21 |
22 | ```js
23 | var Generator = require('audio-generator');
24 | var Speaker = require('audio-speaker');
25 | var RenderStream = require('audio-render');
26 | var isBrowser = require('is-browser');
27 |
28 |
29 | //create rendering stream from passed options
30 | var renderer = RenderStream({
31 | //custom rendering function, can be passed instead of options
32 | render: function (canvas) {
33 | //see audio-analyser for API
34 | var fdata = this.getFrequencyData();
35 | var waveform = this.getTimeData(size);
36 |
37 | //or use web-audio-api AnalyserNode methods here
38 | this.getFloatFrequencyData(new Float32Array(self.frequencyBinCount));
39 | this.getFloatTimeDomainData(new Float32Array(self.fftSize));
40 | },
41 |
42 | //channel number to render, 0 - L, 1 - R, ...
43 | channel: 0,
44 |
45 | //FPS (node only)
46 | framesPerSecond: 20,
47 |
48 | //max amount of data to store, number of samples
49 | bufferSize: 44100,
50 |
51 | //custom canvas (optinal), if you need to render along with other renderer
52 | canvas: undefined,
53 |
54 | //Analysis options
55 |
56 | //Magnitude diapasone, in dB
57 | minDecibels: -100,
58 | maxDecibels: 0,
59 |
60 | // Number of points to grab for fft
61 | fftSize: 1024,
62 |
63 | // Number of points to plot for fft
64 | frequencyBinCount: 1024/2,
65 |
66 | // Smoothing, or the priority of the old data over the new data
67 | smoothingTimeConstant: 0.2
68 |
69 | //...any pcm format options, if required. See pcm-util below.
70 | });
71 |
72 |
73 | //Depending on the enviromnent, expose canvas
74 | isBrowser && document.body.appendChild(renderer.canvas);
75 |
76 | renderer.on('render', function (canvas, data) {
77 | process.stdout.write(canvas._canvas.frame());
78 | });
79 |
80 |
81 | //If renderer is not piped, it works as a sink, else - as pass-through
82 | Generator().pipe(renderer).pipe(Speaker());
83 | ```
84 |
85 | ## Related
86 |
87 | > [audio-analyser](https://npmjs.org/package/audio-analyser) — audio analyser stream.
88 | > [audio-spectrum](https://npmjs.org/package/audio-spectrum) — render audio spectrum.
89 | > [audio-spectrogram](https://npmjs.org/package/audio-spectrogram) — render audio spectrogram.
90 | > [audio-waveform](https://npmjs.org/package/audio-waveform) — render audio waveform.
91 | > [audio-stat](https://npmjs.org/package/audio-stat) — render any kind of audio info: waveform, spectrogram etc.
92 | > [audio-spiral](https://npmjs.org/package/audio-spiral) — render spiral spectrogram, based on audio-render.
93 | > [drawille-canvas](https://github.com/madbence/node-drawille-canvas) — node/browser canvas class.
94 | > [pcm-util](https://npmjs.org/package/pcm-util) — utils for work with pcm-streams.
--------------------------------------------------------------------------------