diff --git a/.bob.json b/.bob.json new file mode 100644 index 0000000..3e77e7c --- /dev/null +++ b/.bob.json @@ -0,0 +1,21 @@ +{ + "build": "clean lint complexity test coverage test-integration doc", + "lint": { + "type": "jshint" + }, + "complexity": { + "type": "plato" + }, + "test": { + "type": "buster" + }, + "coverage": { + "type": "buster-istanbul" + }, + "test-integration": { + "type": "buster" + }, + "doc": { + "type": "dox-foundation" + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8bf0050 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.bob +.DS_Store +node_modules +npm-debug.log diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..a5aaaed --- /dev/null +++ b/.jshintrc @@ -0,0 +1,3 @@ +{ + "esnext": true +} diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..f2648f6 --- /dev/null +++ b/.npmignore @@ -0,0 +1,14 @@ +.bob +.bob.json +.DS_Store +.git +.gitignore +.jshintrc +.npmignore +.travis.yml +avatar.jpg +node_modules +npm-debug.log +screenshots +test +test-integration diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..ffe08d6 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +language: node_js +node_js: + - "0.11" + - "0.10" +before_install: "npm install -g bob --loglevel error" +script: "bob build" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..7e4d66b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,2 @@ +### 0.0.1 +* Initial version diff --git a/README.md b/README.md new file mode 100644 index 0000000..3f06d1b --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +Avatar + +[![Build Status](https://secure.travis-ci.org/cliffano/roombox.png?branch=master)](http://travis-ci.org/cliffano/roombox) +[![Dependencies Status](https://david-dm.org/cliffano/roombox.png)](http://david-dm.org/cliffano/roombox) +[![Published Version](https://badge.fury.io/js/roombox.png)](http://badge.fury.io/js/roombox) +
+[![npm Badge](https://nodei.co/npm/roombox.png)](http://npmjs.org/package/roombox) + +Roombox +------- + +Roombox is a Roomba boombox. + +This is handy when you want to turn your [Roomba vacuum cleaner](http://en.wikipedia.org/wiki/Roomba) into a boombox. + +Installation +------------ + + npm install -g roombox + +Usage +----- + diff --git a/lib/converters/abc.js b/lib/converters/abc.js new file mode 100644 index 0000000..d26b40d --- /dev/null +++ b/lib/converters/abc.js @@ -0,0 +1,43 @@ +var abcnode = require('abcnode'); + +// reasonably pleasant Roomba song notes between note numbers 60 - 83 +const BASE = 60, + ROOMBA_NOTES = [ + 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', + 'c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#', 'a', 'a#', 'b' + ], + SANITISE = ['!', '\\\\', 'Z:.+']; + +function convert(data) { + + SANITISE.forEach(function (pattern) { + data = data.replace(new RegExp(pattern), ''); + }); + + var parsed = abcnode.parse(data), + song = { + title: parsed.header.title, + by: parsed.header.composer, + notes: [] + }; + + parsed.song.forEach(function (x) { + x.forEach(function (y) { + y.forEach(function (z) { + z.chords.forEach(function (chord) { + chord.notes.forEach(function (note) { + var number = ROOMBA_NOTES.indexOf(note.note); + if (number !== -1) { + song.notes.push(number + BASE); + song.notes.push(note.duration); + } + }); + }); + }); + }); + }); + + return song; +} + +exports.convert = convert; \ No newline at end of file diff --git a/lib/playlist.js b/lib/playlist.js new file mode 100644 index 0000000..e69de29 diff --git a/lib/roombox.js b/lib/roombox.js new file mode 100644 index 0000000..e69de29 diff --git a/package.json b/package.json new file mode 100644 index 0000000..f832e33 --- /dev/null +++ b/package.json @@ -0,0 +1,51 @@ +{ + "name": "roombox", + "description": "Roomba boombox", + "keywords": [ + "roomba", + "boombox", + "abc notation", + "music" + ], + "version": "0.0.1", + "homepage": "http://github.com/cliffano/roombox", + "author": "Cliffano Subagio (http://blog.cliffano.com)", + "contributors": [ + "All contributors (https://github.com/cliffano/roombox/graphs/contributors)" + ], + "main": "./lib/roombox", + "bin": { + "roombox": "./bin/roombox" + }, + "preferGlobal": false, + "repository": { + "type": "git", + "url": "http://github.com/cliffano/roombox.git" + }, + "bugs": { + "url": "http://github.com/cliffano/roombox/issues" + }, + "directories": { + "bin": "./bin", + "lib": "./lib", + "test": "./test" + }, + "dependencies": { + "abcnode": "http://github.com/cliffano/abcnode/tarball/master", + "roomba": "~0.0.1" + }, + "devDependencies": { + "buster-node": "~0.7.0", + "referee": "~1.0.1" + }, + "scripts": {}, + "engines": { + "node": ">= 0.8.0" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://github.com/cliffano/roombox/raw/master/LICENSE" + } + ] +} diff --git a/test/converters/abc.js b/test/converters/abc.js new file mode 100644 index 0000000..73f3cc9 --- /dev/null +++ b/test/converters/abc.js @@ -0,0 +1,57 @@ +var buster = require('buster-node'), + abc = require('../../lib/converters/abc'), + referee = require('referee'), + assert = referee.assert; + +buster.testCase('abc - convert', { + 'should convert abc notation to Roomba song data': function () { + var data = [ + 'X:1', + 'T:Hey Jude', + 'C:The Beatles', + 'L:1/8', + 'Q:140', + 'M:4/4', + 'K:C', + 'z6G2|[E2C,2]C,2[zC,]E[GC,]A|[D2G,2]G,2[z2G,2][DG,]E|[F2G,2][c2G,2]G,c[BG,]G|[AF,]G/F/[E2C,2]C,2[zC,]G|[AF,]AF,A[d/F,/]cB/F,/c/A|[G2C,2]C,2[CC,]D[EC,]A|' + ]; + var song = abc.convert(data.join('\n')); + assert.equals(song.title, 'Hey Jude'); + assert.equals(song.by, 'The Beatles'); + assert.equals(song.notes, [67, 64, 64, 64, 64, 32, 67, 32, 69, 32, 62, 64, 62, 32, 64, 32, 65, 64, 72, 64, 72, 32, 71, 32, 67, 32, 69, 32, 67, 16, 65, 16, 64, 64, 67, 32, 69, 32, 69, 32, 69, 32, 74, 16, 72, 32, 71, 16, 72, 16, 69, 32, 67, 64, 60, 32, 62, 32, 64, 32, 69, 32]); + }, + 'should sanitise invalid ABC 1.6 data': function () { + var data = [ + 'X:1', + 'T:Hey Jude!', + 'C:The Beatles', + 'L:1/8', + 'Q:140', + 'M:4/4', + 'K:C', + 'z6G2|[E2C,2]C,2[zC,]E[GC,]A|[D2G,2]G,2[z2G,2][DG,]E|[F2G,2][c2G,2]G,c[BG,]G|[AF,]G/F/[E2C,2]C,2[zC,]G|[AF,]AF,A[d/F,/]cB/F,/c/A|[G2C,2]C,2[CC,]D[EC,]A|\\', + 'Z: edited by' + ]; + var song = abc.convert(data.join('\n')); + assert.equals(song.title, 'Hey Jude'); + assert.equals(song.by, 'The Beatles'); + assert.equals(song.notes, [67, 64, 64, 64, 64, 32, 67, 32, 69, 32, 62, 64, 62, 32, 64, 32, 65, 64, 72, 64, 72, 32, 71, 32, 67, 32, 69, 32, 67, 16, 65, 16, 64, 64, 67, 32, 69, 32, 69, 32, 69, 32, 74, 16, 72, 32, 71, 16, 72, 16, 69, 32, 67, 64, 60, 32, 62, 32, 64, 32, 69, 32]); + }, + 'should throw error when there is invalid syntax': function () { + var data = [ + 'X:1', + 'T:Hey Jude!', + 'C:The Beatles', + 'L:1/8', + 'Q:140', + 'M:4/4', + 'K:C', + 'z6G2|[E2C,|\\' + ]; + try { + abc.convert(data.join('\n')); + } catch (e) { + assert.match(e, 'SyntaxError'); + } + } +}); \ No newline at end of file