├── .gitignore ├── LICENSE ├── README.md ├── package.json ├── stft.js └── test └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules/* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2013 Mikola Lysenko 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | stft 2 | ==== 3 | A streaming-ish [short time Fourier transform](http://en.wikipedia.org/wiki/Short-time_Fourier_transform). 4 | 5 | ## Example 6 | ```javascript 7 | var shortTimeFT = require("stft") 8 | 9 | 10 | function onFreq(re, im) { 11 | //Frequency stuff. Process it here 12 | istft(re, im) 13 | } 14 | 15 | function onTime(v) { 16 | //Got data, emit it here 17 | console.log("out frame:", v) 18 | } 19 | 20 | var stft = shortTimeFT(1, 1024, onFreq) 21 | var istft = shortTimeFT(-1, 1024, onTime) 22 | 23 | //Feed stuff into signal 24 | stft(new Float32Array([1, 0, 0, 0, ... ]) 25 | ``` 26 | 27 | ## Install 28 | 29 | npm install stft 30 | 31 | ### `require("stft")(direction, frame_size, ondata[, options])` 32 | Creates a function for processing a signal with a short time Fourier transform. 33 | 34 | * `direction` is a flag that determines whether the stft is forward or inverse 35 | * `frame_size` is the size of a frame for the stft 36 | * `ondata` is a callback that gets fired whenever data is ready to be processed 37 | * `options` is an optional object that takes the following parameters 38 | 39 | + `options.hop_size` the amount of samples between stft hops 40 | + `options.window_func` a windowing function, which takes a parameter from `[0,1]` and returns a weight 41 | 42 | **Returns** A function that can be called with a frame (either real or complex) that adds a chunk of data to the stft queue 43 | 44 | ### `require("stft").stft(frame_size, ondata[, options])` 45 | Short cut for `require("stft")(1, frame_size, ondata, options)` 46 | 47 | ### `require("stft").istft(frame_size, ondata[, options])` 48 | Short cut for `require("stft")(-1, frame_size, ondata, options)` 49 | 50 | ## Credits 51 | (c) 2013 Mikola Lysenko. MIT License 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stft", 3 | "version": "0.0.0", 4 | "description": "Short time Fourier transform", 5 | "main": "stft.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "dependencies": { 10 | "ndarray": "~0.2.4", 11 | "ndarray-fft": "~0.0.2" 12 | }, 13 | "devDependencies": { 14 | "tape": "~1.0.4" 15 | }, 16 | "scripts": { 17 | "test": "tap test/*.js" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git://github.com/mikolalysenko/stft.git" 22 | }, 23 | "keywords": [ 24 | "short", 25 | "time", 26 | "fourier", 27 | "transform", 28 | "fft", 29 | "stft", 30 | "audio", 31 | "dsp", 32 | "signal", 33 | "processing" 34 | ], 35 | "author": "Mikola Lysenko", 36 | "license": "MIT", 37 | "readmeFilename": "README.md", 38 | "gitHead": "5f024f4ae91c64a9f00f3e91782c0b0151e16fc1", 39 | "bugs": { 40 | "url": "https://github.com/mikolalysenko/stft/issues" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /stft.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | var ndarray = require("ndarray") 4 | var fft = require("ndarray-fft") 5 | 6 | function hannWindowAnalysis(t) { 7 | return 0.5 * (1.0 - Math.cos(2.0 * Math.PI * t)); 8 | } 9 | 10 | function hannWindowSynthesis(t) { 11 | return hannWindowAnalysis(t) * 2.0 / 3.0 12 | } 13 | 14 | function initWindow(frame_size, window_func) { 15 | var ftwindow = new Float32Array(frame_size) 16 | for(var i=0; i>>2 26 | var buffer = new Float32Array(frame_size * 2) 27 | var ptr = 0 28 | var window = initWindow(frame_size, options.window_func||hannWindowAnalysis) 29 | var out_x = new Float32Array(frame_size) 30 | var out_y = new Float32Array(frame_size) 31 | var real = ndarray(out_x) 32 | var imag = ndarray(out_y) 33 | 34 | return function stft(frame) { 35 | var n = frame_size 36 | var i, j, k 37 | var W = window, B = buffer, X = out_x, Y = out_y 38 | 39 | //Copy data into buffer 40 | B.set(frame, ptr) 41 | ptr += n 42 | 43 | //Emit frames 44 | for(j=0; j+n<=ptr; j+=hop_size) { 45 | for(i=0; i>>2 68 | var buffer = new Float32Array(frame_size * 2) 69 | var output = buffer.subarray(0, frame_size) 70 | var sptr = 0 71 | var eptr = 0 72 | var window = initWindow(frame_size, options.window_func||hannWindowSynthesis) 73 | var real = ndarray(window) 74 | var imag = ndarray(window) 75 | 76 | return function istft(X, Y) { 77 | var n = frame_size 78 | var i, j, k 79 | var W = window, B = buffer 80 | 81 | //FFT input signal 82 | real.data = X 83 | imag.data = Y 84 | fft(-1, real, imag) 85 | 86 | //Overlap-add 87 | k = eptr 88 | for(i=0, j=sptr; j= n) { 99 | onistft(output) 100 | for(i=0, j=n; i= 0) { 111 | return forwardSTFT(frame_size, ondata, options) 112 | } else { 113 | return inverseSTFT(frame_size, ondata, options) 114 | } 115 | } 116 | 117 | module.exports = STFT 118 | module.exports.stft = forwardSTFT 119 | module.exports.istft = inverseSTFT -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var STFT = require("../stft.js") 2 | 3 | function stftPassThru(frame_size, input) { 4 | var stft = STFT(1, frame_size, onfft) 5 | var istft = STFT(-1, frame_size, onifft) 6 | var output = new Float32Array(input.length) 7 | var in_ptr = 0 8 | var out_ptr = 0 9 | 10 | function onfft(x, y) { 11 | istft(x, y) 12 | } 13 | 14 | function onifft(v) { 15 | console.log(Array.prototype.slice.call(v)) 16 | for(var i=0; i