From a4279342d0d6c3ad92b04afff4c306ce55f10afc Mon Sep 17 00:00:00 2001
From: Ben Burwell
Date: Sat, 1 Aug 2015 22:28:12 -0400
Subject: start this puppy up
---
.travis.yml | 5 ++
package.json | 21 +++++
src/utils.js | 106 ++++++++++++++++++++++++
test/test_denormalize.js | 56 +++++++++++++
test/test_normalize.js | 207 +++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 395 insertions(+)
create mode 100644 .travis.yml
create mode 100644 package.json
create mode 100644 src/utils.js
create mode 100644 test/test_denormalize.js
create mode 100644 test/test_normalize.js
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..7ce05b5
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,5 @@
+language: node_js
+node_js:
+ - "0.12"
+script:
+ - npm test
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..876842d
--- /dev/null
+++ b/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "solfege",
+ "version": "0.0.1",
+ "description": "A solfege database",
+ "main": "src/index.js",
+ "scripts": {
+ "test": "./node_modules/.bin/mocha -u tdd --reporter spec"
+ },
+ "keywords": [
+ "solfege"
+ ],
+ "author": "Ben Burwell ",
+ "license": "MIT",
+ "dependencies": {
+ "pg": "^4.4.1"
+ },
+ "devDependencies": {
+ "mocha": "^2.2.5",
+ "should": "^7.0.2"
+ }
+}
diff --git a/src/utils.js b/src/utils.js
new file mode 100644
index 0000000..f2d1dc1
--- /dev/null
+++ b/src/utils.js
@@ -0,0 +1,106 @@
+var fs = require('fs');
+
+module.exports = {
+
+ // Take some solfege input and normalize it
+ normalize: function(str) {
+ var tokens = str.toLowerCase().split(/\s+/);
+ var normalized = '';
+ var table = {
+ 'do': 'a',
+ 'do+': 'b',
+ 'do#': 'b',
+ 'doh': 'a',
+ 'doh+': 'b',
+ 'doh#': 'b',
+ 're-': 'b',
+ 'reb': 'b',
+ 're': 'c',
+ 're+': 'd',
+ 're#': 'd',
+ 'mi-': 'd',
+ 'mib': 'd',
+ 'mi': 'e',
+ 'fa': 'f',
+ 'fa+': 'g',
+ 'fa#': 'g',
+ 'so-': 'g',
+ 'sob': 'g',
+ 'so': 'h',
+ 'so+': 'i',
+ 'so#': 'i',
+ 'sol-': 'g',
+ 'solb': 'g',
+ 'sol': 'h',
+ 'sol+': 'i',
+ 'sol#': 'i',
+ 'la-': 'i',
+ 'lab': 'i',
+ 'la': 'j',
+ 'la+': 'k',
+ 'la#': 'k',
+ 'ti-': 'k',
+ 'tib': 'k',
+ 'ti': 'l',
+ 'si-': 'k',
+ 'sib': 'k',
+ 'si': 'l'
+ };
+
+ for (var i = 0; i < tokens.length; i++) {
+ if (table[tokens[i]]) {
+ normalized += table[tokens[i]];
+ }
+ }
+
+ return normalized;
+ },
+
+ // Take some solfege from the DB and translate it back
+ // to something readable
+ denormalize: function(str) {
+ var table = {
+ 'a': 'do',
+ 'b': 'do+',
+ 'c': 're',
+ 'd': 're+',
+ 'e': 'mi',
+ 'f': 'fa',
+ 'g': 'fa+',
+ 'h': 'so',
+ 'i': 'so+',
+ 'j': 'la',
+ 'k': 'la+',
+ 'l': 'ti'
+ };
+ var ret = '';
+
+ for (var i = 0; i < str.length; i++) {
+ ret += table[str.charAt(i)] + ' ';
+ }
+
+ return ret.trim();
+ },
+
+ // Initialize the SQL database
+ initializeDatabase: function(db, done) {
+
+ // Fetch the SQL we need to run
+ fs.readFile('../db/schema.sql', function(err, sql) {
+ if (err) {
+ return console.error('Error reading SQL from file', err);
+ }
+
+ // Execute the query
+ db.query(sql, function(err, result) {
+
+ if (err) {
+ console.error('Error executing SQL query', err);
+ }
+
+ // Run the callback
+ done();
+ });
+ });
+ }
+};
diff --git a/test/test_denormalize.js b/test/test_denormalize.js
new file mode 100644
index 0000000..5ac6464
--- /dev/null
+++ b/test/test_denormalize.js
@@ -0,0 +1,56 @@
+var should = require('should');
+var denormalize = require('../src/utils').denormalize;
+
+describe('Denormalize', function() {
+ it('should denormalize a', function() {
+ denormalize('a').should.be.exactly('do');
+ });
+
+ it('should denormalize b', function() {
+ denormalize('b').should.be.exactly('do+');
+ });
+
+ it('should denormalize c', function() {
+ denormalize('c').should.be.exactly('re');
+ });
+
+ it('should denormalize d', function() {
+ denormalize('d').should.be.exactly('re+');
+ });
+
+ it('should denormalize e', function() {
+ denormalize('e').should.be.exactly('mi');
+ });
+
+ it('should denormalize f', function() {
+ denormalize('f').should.be.exactly('fa');
+ });
+
+ it('should denormalize g', function() {
+ denormalize('g').should.be.exactly('fa+');
+ });
+
+ it('should denormalize h', function() {
+ denormalize('h').should.be.exactly('so');
+ });
+
+ it('should denormalize i', function() {
+ denormalize('i').should.be.exactly('so+');
+ });
+
+ it('should denormalize j', function() {
+ denormalize('j').should.be.exactly('la');
+ });
+
+ it('should denormalize k', function() {
+ denormalize('k').should.be.exactly('la+');
+ });
+
+ it('should denormalize l', function() {
+ denormalize('l').should.be.exactly('ti');
+ });
+
+ it('should denormalize multiple syllables', function() {
+ denormalize('ace').should.be.exactly('do re mi');
+ });
+});
diff --git a/test/test_normalize.js b/test/test_normalize.js
new file mode 100644
index 0000000..cfc7d15
--- /dev/null
+++ b/test/test_normalize.js
@@ -0,0 +1,207 @@
+var should = require('should');
+var normalize = require('../src/utils').normalize;
+
+describe('Normalize', function() {
+
+ describe('Uppercasing', function() {
+ it('should normalize uppercase input', function() {
+ normalize('DO').should.be.exactly('a');
+ });
+ });
+
+ describe('Basic tests', function() {
+
+ describe('A', function() {
+ it('should convert do to a', function() {
+ normalize('do').should.be.exactly('a');
+ });
+
+ it('should convert doh to a', function() {
+ normalize('doh').should.be.exactly('a');
+ });
+ });
+
+ describe('B', function() {
+ it('should convert do+ to b', function() {
+ normalize('do+').should.be.exactly('b');
+ });
+
+ it('should convert do# to b', function() {
+ normalize('do#').should.be.exactly('b');
+ });
+
+ it('should convert doh+ to b', function() {
+ normalize('doh+').should.be.exactly('b');
+ });
+
+ it('should convert doh# to b', function() {
+ normalize('doh#').should.be.exactly('b');
+ });
+
+ it('should convert re- to b', function() {
+ normalize('re-').should.be.exactly('b');
+ });
+
+ it('should convert reb to b', function() {
+ normalize('reb').should.be.exactly('b');
+ });
+ });
+
+ describe('C', function() {
+ it('should convert re to c', function() {
+ normalize('re').should.be.exactly('c');
+ });
+ });
+
+ describe('D', function() {
+ it('should convert re+ to d', function() {
+ normalize('re+').should.be.exactly('d');
+ });
+
+ it('should convert re# to d', function() {
+ normalize('re#').should.be.exactly('d');
+ });
+
+ it('should convert mi- to d', function() {
+ normalize('mi-').should.be.exactly('d');
+ });
+
+ it('should convert mib to d', function() {
+ normalize('mib').should.be.exactly('d');
+ });
+ });
+
+ describe('E', function() {
+ it('should convert mi to e', function() {
+ normalize('mi').should.be.exactly('e');
+ });
+ });
+
+ describe('F', function() {
+ it('should convert fa to f', function() {
+ normalize('fa').should.be.exactly('f');
+ });
+ });
+
+ describe('G', function() {
+ it('should convert fa+ to g', function() {
+ normalize('fa+').should.be.exactly('g');
+ });
+
+ it('should convert fa# to g', function() {
+ normalize('fa#').should.be.exactly('g');
+ });
+
+ it('should convert so- to g', function() {
+ normalize('so-').should.be.exactly('g');
+ });
+
+ it('should convert sob to g', function() {
+ normalize('sob').should.be.exactly('g');
+ });
+
+ it('should convert sol- to g', function() {
+ normalize('sol-').should.be.exactly('g');
+ });
+
+ it('should convert solb to g', function() {
+ normalize('solb').should.be.exactly('g');
+ });
+ });
+
+ describe('H', function() {
+ it('should convert so to h', function() {
+ normalize('so').should.be.exactly('h');
+ });
+
+ it('should convert sol to h', function() {
+ normalize('sol').should.be.exactly('h');
+ });
+ });
+
+ describe('I', function() {
+ it('should convert so+ to i', function() {
+ normalize('so+').should.be.exactly('i');
+ });
+
+ it('should convert so# to i', function() {
+ normalize('so#').should.be.exactly('i');
+ });
+
+ it('should convert sol+ to i', function() {
+ normalize('sol+').should.be.exactly('i');
+ });
+
+ it('should convert sol# to i', function() {
+ normalize('sol#').should.be.exactly('i');
+ });
+
+ it('should convert la- to i', function() {
+ normalize('la-').should.be.exactly('i');
+ });
+
+ it('should convert lab to i', function() {
+ normalize('lab').should.be.exactly('i');
+ });
+ });
+
+ describe('J', function() {
+ it('should convert la to j', function() {
+ normalize('la').should.be.exactly('j');
+ });
+ });
+
+ describe('K', function() {
+ it('should convert la+ to k', function() {
+ normalize('la+').should.be.exactly('k');
+ });
+
+ it('should convert la# to k', function() {
+ normalize('la#').should.be.exactly('k');
+ });
+
+ it('should convert ti- to k', function() {
+ normalize('ti-').should.be.exactly('k');
+ });
+
+ it('should convert tib to k', function() {
+ normalize('tib').should.be.exactly('k');
+ });
+
+ it('should convert si- to k', function() {
+ normalize('si-').should.be.exactly('k');
+ });
+
+ it('should convert sib to k', function() {
+ normalize('sib').should.be.exactly('k');
+ });
+ });
+
+ describe('L', function() {
+ it('should convert ti to l', function() {
+ normalize('ti').should.be.exactly('l');
+ });
+
+ it('should convert si to l', function() {
+ normalize('si').should.be.exactly('l');
+ });
+ });
+
+ });
+
+ describe('Challenging input', function() {
+ it('should correctly interpret multiple syllables', function() {
+ normalize('do re mi').should.be.exactly('ace');
+ });
+
+ it('should correctly tokenize unusual spacing', function() {
+ normalize('do re mi').should.be.exactly('ace');
+ normalize('do\
+ re mi').should.be.exactly('ace');
+ });
+
+ it('should ignore non-tokenizable input', function() {
+ normalize('do asdn3 aweh fnhi re 2hha 1nnua mi').should.be.exactly('ace');
+ });
+ });
+});
--
cgit v1.2.3
From d35ce687049062e47c7154151f048e446bbb077b Mon Sep 17 00:00:00 2001
From: Ben Burwell
Date: Sun, 2 Aug 2015 17:29:12 -0400
Subject: rename test files
---
test/denormalize.js | 56 +++++++++++++
test/normalize.js | 207 +++++++++++++++++++++++++++++++++++++++++++++++
test/test_denormalize.js | 56 -------------
test/test_normalize.js | 207 -----------------------------------------------
4 files changed, 263 insertions(+), 263 deletions(-)
create mode 100644 test/denormalize.js
create mode 100644 test/normalize.js
delete mode 100644 test/test_denormalize.js
delete mode 100644 test/test_normalize.js
diff --git a/test/denormalize.js b/test/denormalize.js
new file mode 100644
index 0000000..5ac6464
--- /dev/null
+++ b/test/denormalize.js
@@ -0,0 +1,56 @@
+var should = require('should');
+var denormalize = require('../src/utils').denormalize;
+
+describe('Denormalize', function() {
+ it('should denormalize a', function() {
+ denormalize('a').should.be.exactly('do');
+ });
+
+ it('should denormalize b', function() {
+ denormalize('b').should.be.exactly('do+');
+ });
+
+ it('should denormalize c', function() {
+ denormalize('c').should.be.exactly('re');
+ });
+
+ it('should denormalize d', function() {
+ denormalize('d').should.be.exactly('re+');
+ });
+
+ it('should denormalize e', function() {
+ denormalize('e').should.be.exactly('mi');
+ });
+
+ it('should denormalize f', function() {
+ denormalize('f').should.be.exactly('fa');
+ });
+
+ it('should denormalize g', function() {
+ denormalize('g').should.be.exactly('fa+');
+ });
+
+ it('should denormalize h', function() {
+ denormalize('h').should.be.exactly('so');
+ });
+
+ it('should denormalize i', function() {
+ denormalize('i').should.be.exactly('so+');
+ });
+
+ it('should denormalize j', function() {
+ denormalize('j').should.be.exactly('la');
+ });
+
+ it('should denormalize k', function() {
+ denormalize('k').should.be.exactly('la+');
+ });
+
+ it('should denormalize l', function() {
+ denormalize('l').should.be.exactly('ti');
+ });
+
+ it('should denormalize multiple syllables', function() {
+ denormalize('ace').should.be.exactly('do re mi');
+ });
+});
diff --git a/test/normalize.js b/test/normalize.js
new file mode 100644
index 0000000..cfc7d15
--- /dev/null
+++ b/test/normalize.js
@@ -0,0 +1,207 @@
+var should = require('should');
+var normalize = require('../src/utils').normalize;
+
+describe('Normalize', function() {
+
+ describe('Uppercasing', function() {
+ it('should normalize uppercase input', function() {
+ normalize('DO').should.be.exactly('a');
+ });
+ });
+
+ describe('Basic tests', function() {
+
+ describe('A', function() {
+ it('should convert do to a', function() {
+ normalize('do').should.be.exactly('a');
+ });
+
+ it('should convert doh to a', function() {
+ normalize('doh').should.be.exactly('a');
+ });
+ });
+
+ describe('B', function() {
+ it('should convert do+ to b', function() {
+ normalize('do+').should.be.exactly('b');
+ });
+
+ it('should convert do# to b', function() {
+ normalize('do#').should.be.exactly('b');
+ });
+
+ it('should convert doh+ to b', function() {
+ normalize('doh+').should.be.exactly('b');
+ });
+
+ it('should convert doh# to b', function() {
+ normalize('doh#').should.be.exactly('b');
+ });
+
+ it('should convert re- to b', function() {
+ normalize('re-').should.be.exactly('b');
+ });
+
+ it('should convert reb to b', function() {
+ normalize('reb').should.be.exactly('b');
+ });
+ });
+
+ describe('C', function() {
+ it('should convert re to c', function() {
+ normalize('re').should.be.exactly('c');
+ });
+ });
+
+ describe('D', function() {
+ it('should convert re+ to d', function() {
+ normalize('re+').should.be.exactly('d');
+ });
+
+ it('should convert re# to d', function() {
+ normalize('re#').should.be.exactly('d');
+ });
+
+ it('should convert mi- to d', function() {
+ normalize('mi-').should.be.exactly('d');
+ });
+
+ it('should convert mib to d', function() {
+ normalize('mib').should.be.exactly('d');
+ });
+ });
+
+ describe('E', function() {
+ it('should convert mi to e', function() {
+ normalize('mi').should.be.exactly('e');
+ });
+ });
+
+ describe('F', function() {
+ it('should convert fa to f', function() {
+ normalize('fa').should.be.exactly('f');
+ });
+ });
+
+ describe('G', function() {
+ it('should convert fa+ to g', function() {
+ normalize('fa+').should.be.exactly('g');
+ });
+
+ it('should convert fa# to g', function() {
+ normalize('fa#').should.be.exactly('g');
+ });
+
+ it('should convert so- to g', function() {
+ normalize('so-').should.be.exactly('g');
+ });
+
+ it('should convert sob to g', function() {
+ normalize('sob').should.be.exactly('g');
+ });
+
+ it('should convert sol- to g', function() {
+ normalize('sol-').should.be.exactly('g');
+ });
+
+ it('should convert solb to g', function() {
+ normalize('solb').should.be.exactly('g');
+ });
+ });
+
+ describe('H', function() {
+ it('should convert so to h', function() {
+ normalize('so').should.be.exactly('h');
+ });
+
+ it('should convert sol to h', function() {
+ normalize('sol').should.be.exactly('h');
+ });
+ });
+
+ describe('I', function() {
+ it('should convert so+ to i', function() {
+ normalize('so+').should.be.exactly('i');
+ });
+
+ it('should convert so# to i', function() {
+ normalize('so#').should.be.exactly('i');
+ });
+
+ it('should convert sol+ to i', function() {
+ normalize('sol+').should.be.exactly('i');
+ });
+
+ it('should convert sol# to i', function() {
+ normalize('sol#').should.be.exactly('i');
+ });
+
+ it('should convert la- to i', function() {
+ normalize('la-').should.be.exactly('i');
+ });
+
+ it('should convert lab to i', function() {
+ normalize('lab').should.be.exactly('i');
+ });
+ });
+
+ describe('J', function() {
+ it('should convert la to j', function() {
+ normalize('la').should.be.exactly('j');
+ });
+ });
+
+ describe('K', function() {
+ it('should convert la+ to k', function() {
+ normalize('la+').should.be.exactly('k');
+ });
+
+ it('should convert la# to k', function() {
+ normalize('la#').should.be.exactly('k');
+ });
+
+ it('should convert ti- to k', function() {
+ normalize('ti-').should.be.exactly('k');
+ });
+
+ it('should convert tib to k', function() {
+ normalize('tib').should.be.exactly('k');
+ });
+
+ it('should convert si- to k', function() {
+ normalize('si-').should.be.exactly('k');
+ });
+
+ it('should convert sib to k', function() {
+ normalize('sib').should.be.exactly('k');
+ });
+ });
+
+ describe('L', function() {
+ it('should convert ti to l', function() {
+ normalize('ti').should.be.exactly('l');
+ });
+
+ it('should convert si to l', function() {
+ normalize('si').should.be.exactly('l');
+ });
+ });
+
+ });
+
+ describe('Challenging input', function() {
+ it('should correctly interpret multiple syllables', function() {
+ normalize('do re mi').should.be.exactly('ace');
+ });
+
+ it('should correctly tokenize unusual spacing', function() {
+ normalize('do re mi').should.be.exactly('ace');
+ normalize('do\
+ re mi').should.be.exactly('ace');
+ });
+
+ it('should ignore non-tokenizable input', function() {
+ normalize('do asdn3 aweh fnhi re 2hha 1nnua mi').should.be.exactly('ace');
+ });
+ });
+});
diff --git a/test/test_denormalize.js b/test/test_denormalize.js
deleted file mode 100644
index 5ac6464..0000000
--- a/test/test_denormalize.js
+++ /dev/null
@@ -1,56 +0,0 @@
-var should = require('should');
-var denormalize = require('../src/utils').denormalize;
-
-describe('Denormalize', function() {
- it('should denormalize a', function() {
- denormalize('a').should.be.exactly('do');
- });
-
- it('should denormalize b', function() {
- denormalize('b').should.be.exactly('do+');
- });
-
- it('should denormalize c', function() {
- denormalize('c').should.be.exactly('re');
- });
-
- it('should denormalize d', function() {
- denormalize('d').should.be.exactly('re+');
- });
-
- it('should denormalize e', function() {
- denormalize('e').should.be.exactly('mi');
- });
-
- it('should denormalize f', function() {
- denormalize('f').should.be.exactly('fa');
- });
-
- it('should denormalize g', function() {
- denormalize('g').should.be.exactly('fa+');
- });
-
- it('should denormalize h', function() {
- denormalize('h').should.be.exactly('so');
- });
-
- it('should denormalize i', function() {
- denormalize('i').should.be.exactly('so+');
- });
-
- it('should denormalize j', function() {
- denormalize('j').should.be.exactly('la');
- });
-
- it('should denormalize k', function() {
- denormalize('k').should.be.exactly('la+');
- });
-
- it('should denormalize l', function() {
- denormalize('l').should.be.exactly('ti');
- });
-
- it('should denormalize multiple syllables', function() {
- denormalize('ace').should.be.exactly('do re mi');
- });
-});
diff --git a/test/test_normalize.js b/test/test_normalize.js
deleted file mode 100644
index cfc7d15..0000000
--- a/test/test_normalize.js
+++ /dev/null
@@ -1,207 +0,0 @@
-var should = require('should');
-var normalize = require('../src/utils').normalize;
-
-describe('Normalize', function() {
-
- describe('Uppercasing', function() {
- it('should normalize uppercase input', function() {
- normalize('DO').should.be.exactly('a');
- });
- });
-
- describe('Basic tests', function() {
-
- describe('A', function() {
- it('should convert do to a', function() {
- normalize('do').should.be.exactly('a');
- });
-
- it('should convert doh to a', function() {
- normalize('doh').should.be.exactly('a');
- });
- });
-
- describe('B', function() {
- it('should convert do+ to b', function() {
- normalize('do+').should.be.exactly('b');
- });
-
- it('should convert do# to b', function() {
- normalize('do#').should.be.exactly('b');
- });
-
- it('should convert doh+ to b', function() {
- normalize('doh+').should.be.exactly('b');
- });
-
- it('should convert doh# to b', function() {
- normalize('doh#').should.be.exactly('b');
- });
-
- it('should convert re- to b', function() {
- normalize('re-').should.be.exactly('b');
- });
-
- it('should convert reb to b', function() {
- normalize('reb').should.be.exactly('b');
- });
- });
-
- describe('C', function() {
- it('should convert re to c', function() {
- normalize('re').should.be.exactly('c');
- });
- });
-
- describe('D', function() {
- it('should convert re+ to d', function() {
- normalize('re+').should.be.exactly('d');
- });
-
- it('should convert re# to d', function() {
- normalize('re#').should.be.exactly('d');
- });
-
- it('should convert mi- to d', function() {
- normalize('mi-').should.be.exactly('d');
- });
-
- it('should convert mib to d', function() {
- normalize('mib').should.be.exactly('d');
- });
- });
-
- describe('E', function() {
- it('should convert mi to e', function() {
- normalize('mi').should.be.exactly('e');
- });
- });
-
- describe('F', function() {
- it('should convert fa to f', function() {
- normalize('fa').should.be.exactly('f');
- });
- });
-
- describe('G', function() {
- it('should convert fa+ to g', function() {
- normalize('fa+').should.be.exactly('g');
- });
-
- it('should convert fa# to g', function() {
- normalize('fa#').should.be.exactly('g');
- });
-
- it('should convert so- to g', function() {
- normalize('so-').should.be.exactly('g');
- });
-
- it('should convert sob to g', function() {
- normalize('sob').should.be.exactly('g');
- });
-
- it('should convert sol- to g', function() {
- normalize('sol-').should.be.exactly('g');
- });
-
- it('should convert solb to g', function() {
- normalize('solb').should.be.exactly('g');
- });
- });
-
- describe('H', function() {
- it('should convert so to h', function() {
- normalize('so').should.be.exactly('h');
- });
-
- it('should convert sol to h', function() {
- normalize('sol').should.be.exactly('h');
- });
- });
-
- describe('I', function() {
- it('should convert so+ to i', function() {
- normalize('so+').should.be.exactly('i');
- });
-
- it('should convert so# to i', function() {
- normalize('so#').should.be.exactly('i');
- });
-
- it('should convert sol+ to i', function() {
- normalize('sol+').should.be.exactly('i');
- });
-
- it('should convert sol# to i', function() {
- normalize('sol#').should.be.exactly('i');
- });
-
- it('should convert la- to i', function() {
- normalize('la-').should.be.exactly('i');
- });
-
- it('should convert lab to i', function() {
- normalize('lab').should.be.exactly('i');
- });
- });
-
- describe('J', function() {
- it('should convert la to j', function() {
- normalize('la').should.be.exactly('j');
- });
- });
-
- describe('K', function() {
- it('should convert la+ to k', function() {
- normalize('la+').should.be.exactly('k');
- });
-
- it('should convert la# to k', function() {
- normalize('la#').should.be.exactly('k');
- });
-
- it('should convert ti- to k', function() {
- normalize('ti-').should.be.exactly('k');
- });
-
- it('should convert tib to k', function() {
- normalize('tib').should.be.exactly('k');
- });
-
- it('should convert si- to k', function() {
- normalize('si-').should.be.exactly('k');
- });
-
- it('should convert sib to k', function() {
- normalize('sib').should.be.exactly('k');
- });
- });
-
- describe('L', function() {
- it('should convert ti to l', function() {
- normalize('ti').should.be.exactly('l');
- });
-
- it('should convert si to l', function() {
- normalize('si').should.be.exactly('l');
- });
- });
-
- });
-
- describe('Challenging input', function() {
- it('should correctly interpret multiple syllables', function() {
- normalize('do re mi').should.be.exactly('ace');
- });
-
- it('should correctly tokenize unusual spacing', function() {
- normalize('do re mi').should.be.exactly('ace');
- normalize('do\
- re mi').should.be.exactly('ace');
- });
-
- it('should ignore non-tokenizable input', function() {
- normalize('do asdn3 aweh fnhi re 2hha 1nnua mi').should.be.exactly('ace');
- });
- });
-});
--
cgit v1.2.3
From 0fb9fa6be86ced26feefd07a310371ee7d9b6185 Mon Sep 17 00:00:00 2001
From: Ben Burwell
Date: Sun, 2 Aug 2015 17:29:36 -0400
Subject: add travis ci status to readme
---
readme.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/readme.md b/readme.md
index a3721fb..6ee70e9 100644
--- a/readme.md
+++ b/readme.md
@@ -1,6 +1,8 @@
Solfège
=======
+
+
[Solfège](https://en.wikipedia.org/wiki/Solf%C3%A8ge) is a system of assigning syllables to musical pitches. This project attempts to enable people to find songs that they just can't quite remember the words for by searching for a solfege phrase.
The solfège scale is: do, re, mi, fa, so, la, ti. In order to simplify searching, a "movable do" is used. This means that do does not always correspond to C; rather, it corresponds to the root of the key that the song is written in.
--
cgit v1.2.3
From 2cde3ec173c57d24e6fb8a31700a7db4eb31564d Mon Sep 17 00:00:00 2001
From: Ben Burwell
Date: Sun, 2 Aug 2015 17:30:10 -0400
Subject: add app.json for heroku
---
app.json | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 app.json
diff --git a/app.json b/app.json
new file mode 100644
index 0000000..4d1b3f2
--- /dev/null
+++ b/app.json
@@ -0,0 +1,5 @@
+{
+ "addons": [
+ "heroku-postgresql:hobby-dev"
+ ]
+}
--
cgit v1.2.3
From 3d0f989cee9d7c426c759588539dd06c14fa70ea Mon Sep 17 00:00:00 2001
From: Ben Burwell
Date: Sun, 2 Aug 2015 17:31:36 -0400
Subject: let's get v1 going here
---
db/schema.sql | 36 ++++++
package.json | 4 +-
src/assets/index.html | 25 ++++
src/assets/thanks.html | 11 ++
src/index.js | 207 ++++++++++++++++++++++++++++++++
src/templates/search_results.html | 34 ++++++
src/templates/submit_song_new.html | 29 +++++
src/templates/submit_song_picklist.html | 15 +++
src/utils.js | 25 ----
9 files changed, 360 insertions(+), 26 deletions(-)
create mode 100644 db/schema.sql
create mode 100644 src/assets/index.html
create mode 100644 src/assets/thanks.html
create mode 100644 src/index.js
create mode 100644 src/templates/search_results.html
create mode 100644 src/templates/submit_song_new.html
create mode 100644 src/templates/submit_song_picklist.html
diff --git a/db/schema.sql b/db/schema.sql
new file mode 100644
index 0000000..a7509da
--- /dev/null
+++ b/db/schema.sql
@@ -0,0 +1,36 @@
+-- Create the phrase table
+-- This will hold the phrases with an associated ID
+-- Phrases will be varchars of solfege syllables normalized as:
+-- a = do
+-- b = do+/re-
+-- c = re
+-- d = re+/mi-
+-- e = mi
+-- f = fa
+-- g = fa+/so-
+-- h = so
+-- i = so+/la-
+-- j = la
+-- k = la+/ti-
+-- l = ti
+CREATE TABLE IF NOT EXISTS phrases (
+ phrase_id BIGSERIAL PRIMARY KEY,
+ solfege VARCHAR(30) NOT NULL UNIQUE
+);
+
+-- Create a table that allows us to have a many-to-many
+-- relationship between phrases and songs (i.e., a phrase can be
+-- contained within multiple songs, and a song can have multiple phrases).
+CREATE TABLE IF NOT EXISTS phrase_song (
+ phrase_id BIGINT NOT NULL,
+ song_id BIGINT NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS songs (
+ song_id BIGSERIAL PRIMARY KEY,
+ title VARCHAR(255),
+ artist_name VARCHAR(255)
+);
+
+-- Now we need an index that will allow us to search more quickly for phrases
+CREATE UNIQUE INDEX phrases_solfege ON phrases (solfege);
diff --git a/package.json b/package.json
index 876842d..fb3d90b 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,9 @@
"author": "Ben Burwell ",
"license": "MIT",
"dependencies": {
- "pg": "^4.4.1"
+ "handlebars": "^3.0.3",
+ "hapi": "^8.8.1",
+ "hapi-postgres": "^1.0.2"
},
"devDependencies": {
"mocha": "^2.2.5",
diff --git a/src/assets/index.html b/src/assets/index.html
new file mode 100644
index 0000000..ada309b
--- /dev/null
+++ b/src/assets/index.html
@@ -0,0 +1,25 @@
+
+
+
+ Solfege search
+
+
+
+
+ Enter some movable-do solfege syllables to search for:
+
+
+
+ The search engine will recognize different forms, such as ti and si, and will understand both + and # as sharp, and - and b as flat.
+
+
+
+
+
diff --git a/src/assets/thanks.html b/src/assets/thanks.html
new file mode 100644
index 0000000..e6f6ff4
--- /dev/null
+++ b/src/assets/thanks.html
@@ -0,0 +1,11 @@
+
+
+
+ Thanks for being awesome!
+
+
+ You rock!
+ Thanks for helping out the solfege project! You gain ∞ life points! :D
+ Head home
+
+
diff --git a/src/index.js b/src/index.js
new file mode 100644
index 0000000..7edcfdb
--- /dev/null
+++ b/src/index.js
@@ -0,0 +1,207 @@
+// require built-in modules
+var fs = require('fs');
+var path = require('path');
+
+// require external libs
+var Hapi = require('hapi');
+
+// require custom libs
+var utils = require('./utils');
+
+var server = new Hapi.Server();
+server.connection({
+ host: 'localhost',
+ port: process.env.PORT || 8000
+});
+
+server.views({
+ engines: {
+ html: require('handlebars')
+ },
+ path: path.join(__dirname, 'templates')
+});
+
+server.register({
+ register: require('hapi-postgres'),
+ options: {
+ uri: process.env.DATABASE_URL || 'postgres://postgres:postgres@127.0.0.1/solfege'
+ }
+}, function(err) {
+ if (err) {
+ console.error('Failed to load hapi-postgres', err);
+ }
+});
+
+server.method('search', function(query, next) {
+ var client = server.plugins['hapi-postgres'].client;
+ var done = server.plugins['hapi-postgres'].done;
+
+ var norm = utils.normalize(query);
+
+ var sql = 'SELECT title, artist_name FROM songs JOIN phrase_song ON (songs.song_id = phrase_song.song_id) WHERE phrase_song.phrase_id IN (SELECT phrase_id FROM phrases WHERE solfege LIKE \'%' + norm + '%\') GROUP BY songs.song_id;';
+ return client.query(sql, function(err, results) {
+ done();
+
+ if (err) {
+ next(err);
+ } else {
+ next(null, results.rows);
+ }
+ });
+});
+
+server.method('getSongsWithSimilarTitle', function(title, next) {
+ var client = server.plugins['hapi-postgres'].client;
+ var done = server.plugins['hapi-postgres'].done;
+
+ var sql = 'SELECT song_id, title, artist_name FROM songs WHERE title @@ plainto_tsquery(\'' + title + '\');';
+ return client.query(sql, function(err, results) {
+ done();
+ if (err) {
+ next(err);
+ } else {
+ next(null, results.rows);
+ }
+ });
+});
+
+server.method('addSongWithPhrase', function(options, next) {
+ var client = server.plugins['hapi-postgres'].client;
+ var done = server.plugins['hapi-postgres'].done;
+
+ if (!options.title || !options.artist_name || !options.solfege) {
+ done();
+ return next(new Error('Missing required title, artist_name, or solfege'));
+ }
+
+ options.solfege = utils.normalize(options.solfege);
+ var sql = 'INSERT INTO songs (title, artist_name) VALUES (\'' + options.title + '\', \'' + options.artist_name + '\'); INSERT INTO phrases (solfege) VALUES (\'' + options.solfege + '\'); INSERT INTO phrase_song (song_id, phrase_id) VALUES ((SELECT CURRVAL(\'songs_song_id_seq\')), (SELECT CURRVAL(\'phrases_phrase_id_seq\')));';
+ return client.query(sql, function(err, results) {
+ done();
+ if (err) {
+ next(err);
+ } else {
+ next(null);
+ }
+ });
+});
+
+server.method('addPhraseToSong', function(options, next) {
+ var client = server.plugins['hapi-postgres'].client;
+ var done = server.plugins['hapi-postgres'].done;
+
+ if (!options.song_id || !options.phrase) {
+ done();
+ return next(new Error('Missing required song_id or phrase'));
+ } else {
+ var solfege = utils.normalize(options.phrase);
+ var sql = 'INSERT INTO phrases (solfege) VALUES (\'' + solfege + '\'); INSERT INTO phrase_song (song_id, phrase_id) VALUES (' + options.song_id + ', (SELECT phrase_id FROM phrases WHERE solfege=\'' + solfege + '\'));';
+ return client.query(sql, function(err, results) {
+ done();
+
+ if (err) {
+ next(new Error('Error adding phrase to song'));
+ } else {
+ next(null);
+ }
+ });
+ }
+});
+
+// search results
+server.route({
+ method: 'GET',
+ path: '/search',
+ handler: function(request, reply) {
+
+ var q = request.query.q;
+
+ server.methods.search(request.query.q, function(err, results) {
+ if (err) {
+ reply('Error processing query: ' + err);
+ } else {
+ reply.view('search_results', {
+ original_query: q,
+ normalized_query: utils.normalize(q),
+ denormalized_query: utils.denormalize(utils.normalize(q)),
+ results: results
+ });
+ }
+ });
+ }
+});
+
+// submit a song
+server.route({
+ method: 'GET',
+ path: '/submit_song',
+ handler: function(request, reply) {
+ server.methods.getSongsWithSimilarTitle(request.query.title, function(err, songs) {
+ if (err) {
+ console.error(err)
+ reply('Error');
+ } else {
+ if (songs.length > 0 && request.query.new != 1) {
+ reply.view('submit_song_picklist', { phrase: request.query.phrase, songs: songs });
+ } else {
+ reply.view('submit_song_new', {
+ title: request.query.title,
+ phrase: request.query.phrase
+ });
+ }
+ }
+ });
+ }
+});
+
+server.route({
+ method: 'POST',
+ path: '/submit_song',
+ handler: function(request, reply) {
+ server.methods.addSongWithPhrase({
+ title: request.payload.title,
+ artist_name: request.payload.artist,
+ solfege: request.payload.phrase
+ }, function(err) {
+ if (err) {
+ console.log(err);
+ reply('Error processing request');
+ } else {
+ reply.redirect('/thanks.html');
+ }
+ });
+ }
+});
+
+server.route({
+ method: 'GET',
+ path: '/add_phrase',
+ handler: function(request, reply) {
+ server.methods.addPhraseToSong({
+ song_id: request.query.id,
+ phrase: request.query.phrase
+ }, function(err) {
+ if (err) {
+ console.error(err);
+ reply('Error processing request');
+ } else {
+ reply.redirect('/thanks.html');
+ }
+ });
+ }
+});
+
+// serve static files
+server.route({
+ method: 'GET',
+ path: '/{filename*}',
+ handler: {
+ directory: {
+ path: path.join(__dirname, 'assets')
+ }
+ }
+});
+
+server.start(function() {
+ console.log('Server running!');
+});
diff --git a/src/templates/search_results.html b/src/templates/search_results.html
new file mode 100644
index 0000000..9bac74f
--- /dev/null
+++ b/src/templates/search_results.html
@@ -0,0 +1,34 @@
+
+
+
+ Solfege search results - {{original_query}}
+
+
+
+
+
+ Solfege search results
+
+
+
+
+
+ {{#each results}}
+ - {{title}} - {{artist_name}}
+ {{/each}}
+
+
+ None of these right? Remebered the song?
+ Submit the song this phrase is from!
+
+
+
+
+
diff --git a/src/templates/submit_song_new.html b/src/templates/submit_song_new.html
new file mode 100644
index 0000000..29d7529
--- /dev/null
+++ b/src/templates/submit_song_new.html
@@ -0,0 +1,29 @@
+
+
+
+ Submit a new song
+
+
+ Submit a new song
+ Tell us about the song (all fields required):
+
+
+
diff --git a/src/templates/submit_song_picklist.html b/src/templates/submit_song_picklist.html
new file mode 100644
index 0000000..b56c43f
--- /dev/null
+++ b/src/templates/submit_song_picklist.html
@@ -0,0 +1,15 @@
+
+
+
+ Submit a song
+
+
+ Did you mean one of these?
+
+ {{#each songs}}
+ - {{title}} by {{artist_name}}
+ {{/each}}
+
+ Nope, it's none of these
+
+
diff --git a/src/utils.js b/src/utils.js
index f2d1dc1..4dc3458 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -1,7 +1,4 @@
-var fs = require('fs');
-
module.exports = {
-
// Take some solfege input and normalize it
normalize: function(str) {
var tokens = str.toLowerCase().split(/\s+/);
@@ -80,27 +77,5 @@ module.exports = {
}
return ret.trim();
- },
-
- // Initialize the SQL database
- initializeDatabase: function(db, done) {
-
- // Fetch the SQL we need to run
- fs.readFile('../db/schema.sql', function(err, sql) {
- if (err) {
- return console.error('Error reading SQL from file', err);
- }
-
- // Execute the query
- db.query(sql, function(err, result) {
-
- if (err) {
- console.error('Error executing SQL query', err);
- }
-
- // Run the callback
- done();
- });
- });
}
};
--
cgit v1.2.3