Skip to content

Commit

Permalink
feat: MP3 encoder (#235)
Browse files Browse the repository at this point in the history
  • Loading branch information
tassoevan authored Jun 4, 2020
1 parent 1d74390 commit a85eb1a
Show file tree
Hide file tree
Showing 14 changed files with 528 additions and 4 deletions.
2 changes: 1 addition & 1 deletion packages/css-in-js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![License: MIT](https://img.shields.io/github/license/RocketChat/@rocket.chat/css-in-js)](https://github.com/RocketChat/Rocket.Chat.Fuselage/blob/master/LICENSE)
[![Twitter: RocketChat](https://img.shields.io/twitter/follow/RocketChat.svg?style=social)](https://twitter.com/RocketChat)

> React Hooks for Fuselage, Rocket.Chat's design system
> Toolset to transpile and use CSS on runtime
### 🏠 [Homepage](https://rocket.chat/Rocket.Chat.Fuselage)

Expand Down
2 changes: 2 additions & 0 deletions packages/mp3-encoder/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/node_modules
/dist
56 changes: 56 additions & 0 deletions packages/mp3-encoder/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
module.exports = {
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/eslint-recommended',
'@rocket.chat/eslint-config',
],
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module',
ecmaVersion: 2018,
warnOnUnsupportedTypeScriptVersion: false,
ecmaFeatures: {
experimentalObjectRestSpread: true,
legacyDecorators: true,
},
},
plugins: ['@typescript-eslint'],
rules: {
'indent': ['error', 2, {
SwitchCase: 1,
}],
'import/order': ['error', {
'newlines-between': 'always',
groups: ['builtin', 'external', 'internal', ['parent', 'sibling', 'index']],
}],
'no-useless-constructor': 'off',
'no-empty-function': 'off',
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/indent': ['error', 2, {
SwitchCase: 1,
}],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/interface-name-prefix': [
'error',
'always'
],
},
env: {
browser: true,
commonjs: true,
es6: true,
node: true,
jest: true
},
settings: {
'import/resolver': {
node: {
extensions: [
'.js',
'.ts',
'.tsx'
],
},
},
},
};
1 change: 1 addition & 0 deletions packages/mp3-encoder/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/dist/
6 changes: 6 additions & 0 deletions packages/mp3-encoder/.lintstagedrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"src/**/*.js": [
"eslint --fix",
"git add"
]
}
49 changes: 49 additions & 0 deletions packages/mp3-encoder/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Welcome to @rocket.chat/mp3-encoder 👋

[![Documentation](https://img.shields.io/badge/documentation-yes-brightgreen.svg)](https://github.com/RocketChat/Rocket.Chat.Fuselage#readme)
[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/RocketChat/Rocket.Chat.Fuselage/graphs/commit-activity)
[![License: MIT](https://img.shields.io/github/license/RocketChat/@rocket.chat/mp3-encoder)](https://github.com/RocketChat/Rocket.Chat.Fuselage/blob/master/LICENSE)
[![Twitter: RocketChat](https://img.shields.io/twitter/follow/RocketChat.svg?style=social)](https://twitter.com/RocketChat)

> A LAME encoder to be used in web workers
### 🏠 [Homepage](https://rocket.chat/Rocket.Chat.Fuselage)

## Install

```sh
yarn add @rocket.chat/mp3-encoder
```

## Run tests

```sh
yarn test
```

## API Reference

<!-- Generated by documentation.js. Update this documentation by updating the source code. -->

### Table of Contents

## Author

👤 **Rocket.Chat**

- Twitter: [@RocketChat](https://twitter.com/RocketChat)
- Github: [@RocketChat](https://github.com/RocketChat)

## 🤝 Contributing

Contributions, issues and feature requests are welcome!

Feel free to check [issues page](https://github.com/RocketChat/Rocket.Chat.Fuselage/issues).

## Show your support

Give a ⭐️ if this project helped you!

* * *

_This README was generated with ❤️ by [readme-md-generator](https://github.com/kefranabg/readme-md-generator)_
6 changes: 6 additions & 0 deletions packages/mp3-encoder/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript',
],
};
64 changes: 64 additions & 0 deletions packages/mp3-encoder/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"name": "@rocket.chat/mp3-encoder",
"version": "0.8.0",
"description": "A LAME encoder to be used in web workers",
"homepage": "https://rocket.chat/Rocket.Chat.Fuselage",
"author": {
"name": "Rocket.Chat",
"url": "https://rocket.chat/"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/RocketChat/Rocket.Chat.Fuselage.git"
},
"bugs": {
"url": "https://github.com/RocketChat/Rocket.Chat.Fuselage/issues"
},
"keywords": [
"rocketchat",
"mp3",
"encoder"
],
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"start": "rollup -c -w",
"build": "rollup -c",
"test": "jest",
"lint": "eslint src --ext .js,.ts",
"lint-staged": "lint-staged",
"docs": "documentation readme src/index.ts --shallow --section='API Reference' --readme-file README.md"
},
"publishConfig": {
"access": "public"
},
"dependencies": {
"lamejs": "^1.2.0"
},
"devDependencies": {
"@babel/core": "^7.6.4",
"@babel/plugin-transform-runtime": "^7.7.6",
"@babel/preset-env": "^7.7.6",
"@babel/preset-typescript": "^7.9.0",
"@rocket.chat/eslint-config": "^0.4.0",
"@rollup/plugin-typescript": "^4.1.1",
"@types/jest": "^25.2.3",
"@typescript-eslint/eslint-plugin": "^2.34.0",
"@typescript-eslint/parser": "^2.34.0",
"babel-eslint": "^10.0.3",
"documentation": "^12.1.2",
"eslint": "^6.5.1",
"eslint-plugin-import": "^2.19.1",
"jest": "^25.1.0",
"lint-staged": "^10.0.8",
"rollup": "^2.1.0",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-peer-deps-external": "^2.2.2"
}
}
40 changes: 40 additions & 0 deletions packages/mp3-encoder/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import path from 'path';

import commonjs from 'rollup-plugin-commonjs';
import external from 'rollup-plugin-peer-deps-external';
import resolve from 'rollup-plugin-node-resolve';
import typescript from '@rollup/plugin-typescript';

import pkg from './package.json';

export default [
{
input: 'src/index.ts',
output: {
dir: path.dirname(pkg.main),
entryFileNames: path.basename(pkg.main),
format: 'cjs',
sourcemap: true,
},
plugins: [
external(),
typescript({ declaration: true, declarationDir: 'dist/' }),
resolve(),
commonjs(),
],
},
{
input: 'src/index.ts',
output: {
file: pkg.module,
format: 'esm',
sourcemap: true,
},
plugins: [
external(),
typescript(),
resolve(),
commonjs(),
],
},
];
42 changes: 42 additions & 0 deletions packages/mp3-encoder/src/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import './index';

declare const self: any;

describe('web worker messages', () => {
beforeEach(() => {
self.onmessage = jest.fn(self.onmessage);
self.postMessage = jest.fn();
});

it('handles init message', () => {
const event = new MessageEvent('message', {
data: {
command: 'init',
},
});
self.dispatchEvent(event);
expect(self.onmessage).toBeCalledTimes(1);
});

it('handles encode message', () => {
const event = new MessageEvent('message', {
data: {
command: 'encode',
buffer: new ArrayBuffer(0),
},
});
self.dispatchEvent(event);
expect(self.onmessage).toBeCalledTimes(1);
});

it('handles finish message', () => {
const event = new MessageEvent('message', {
data: {
command: 'finish',
},
});
self.dispatchEvent(event);
expect(self.onmessage).toBeCalledTimes(1);
expect(self.postMessage).toBeCalledTimes(1);
});
});
68 changes: 68 additions & 0 deletions packages/mp3-encoder/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Mp3Encoder } from 'lamejs';

declare const self: any;

type Config = {
numChannels?: number;
sampleRate?: number;
bitRate?: number;
};

let encoder: Mp3Encoder;
const maxSamples = 1152;
let samplesMono: Int16Array;
let dataBuffer: Int8Array[];

function convertBuffer(arrayBuffer: Float32Array): Int16Array {
const input = new Float32Array(arrayBuffer);
const output = new Int16Array(arrayBuffer.length);

for (let i = 0; i < input.length; i++) {
const s = Math.max(-1, Math.min(1, input[i]));
output[i] = s < 0 ? s * 0x8000 : s * 0x7FFF;
}

return output;
}

function init(config: Config): void {
config = config || {};
encoder = new Mp3Encoder(config.numChannels || 1, config.sampleRate || 44100, config.bitRate || 32);
dataBuffer = [];
}

function encode(arrayBuffer: Float32Array): void {
samplesMono = convertBuffer(arrayBuffer);
let remaining = samplesMono.length;
for (let i = 0; remaining >= 0; i += maxSamples) {
const left = samplesMono.subarray(i, i + maxSamples);
const buffer = encoder.encodeBuffer(left);
dataBuffer.push(new Int8Array(buffer));
remaining -= maxSamples;
}
}

function finish(): void {
const buffer = encoder.flush();
dataBuffer.push(new Int8Array(buffer));
self.postMessage({ command: 'end', buffer: dataBuffer });
dataBuffer = [];
}

function onMessage(event: MessageEvent): void {
switch (event.data.command) {
case 'init':
init(event.data.config);
break;

case 'encode':
encode(event.data.buffer);
break;

case 'finish':
finish();
break;
}
}

self.onmessage = onMessage;
9 changes: 9 additions & 0 deletions packages/mp3-encoder/src/lamejs.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
declare module 'lamejs' {
export class Mp3Encoder {
constructor(numChannels: number, sampleRate: number, bitRate: number);

encodeBuffer(buffer: Int16Array): Iterable<number>;

flush(): Iterable<number>;
}
}
10 changes: 10 additions & 0 deletions packages/mp3-encoder/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["es2015", "webworker"],
"strict": false,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"rootDir": "./src"
}
}
Loading

0 comments on commit a85eb1a

Please sign in to comment.