├── .gitignore
├── LICENSE.md
├── README.md
├── app.js
├── docs
├── README.md
├── _config.yml
└── favicon.ico
├── index.js
├── music
└── .gitignore
├── package.json
├── src
├── baseFile.js
├── scraper.js
└── tablature.js
├── test
└── e-chords.scraper.js
└── views
└── index.pug
/.gitignore:
--------------------------------------------------------------------------------
1 | ### Node ###
2 | # Logs
3 | logs
4 | *.log
5 | npm-debug.log*
6 | yarn-debug.log*
7 | yarn-error.log*
8 |
9 | # Dependency directory
10 | node_modules
11 |
12 | ### Ignoring Music ###
13 | music/music.ino
14 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Thiago Augusto
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # arduino-tablature
2 |
3 | Node.js project that makes a web scraping to get some guitar tablature and transform
4 | it to an Arduino Program compatible with the tone() Function.
5 |
6 | ## About the project
7 |
8 | ### What is a tablature?
9 |
10 | Tablature (or tabulature, or tab for short) is a form of musical notation indicating instrument fingering rather than musical pitches. _- Wikipedia words_
11 |
12 | And it looks like this:
13 |
14 | 
15 |
16 | #### Nice, but what can i do with this project?
17 |
18 | So, with a circuit like that:
19 |
20 | 
21 |
22 | Using this project you can play your favorite songs in your own Arduino.
23 |
24 | ## How to use it (Recommended way)
25 |
26 | First of all, make sure you have [npm and node](https://www.npmjs.com/get-npm) installed.
27 |
28 | ### Installation
29 | Open your terminal and type:
30 |
31 | > sudo npm install -g arduino-tablature
32 |
33 | Now you have the arduino-tablature command available globally
34 |
35 | ### Picking your tablature
36 |
37 | - Go to [CifraClub's WebSite](https://www.cifraclub.com.br "CifraClub's Website") and search for your song, **which has a tablature on it.**
38 |
39 | #### Example:
40 |
41 | > https://www.cifraclub.com.br/natiruts/andei-so/
42 |
43 | ### Running the code
44 | Then execute in the terminal, with your url in the url param:
45 |
46 | > arduino-tablature --url=https://www.cifraclub.com.br/natiruts/andei-so/
47 |
48 | ### Uploading to Arduino
49 |
50 | After that a **music.ino** file will be generated, inside the music folder, and you will be able to [upload it to your arduino](https://www.arduino.cc/en/Guide/HomePage) using the Arduino IDE or others.
51 |
52 | ### Alternative way
53 |
54 | #### Installation
55 |
56 | 1. start [cloning/downloading](https://github.com/ThiagoAugustoSM/arduino-tablature/zipball/master) this repository. _if you download a .zip or .tar.gz file, unzip the file._
57 | 2. In the terminal navigate to the folder, then run:
58 |
59 | > npm install
60 |
61 | After it all the dependencies packages are all set.
62 |
63 | #### Picking your tablature
64 |
65 | - Go to [CifraClub's WebSite](https://www.cifraclub.com.br "CifraClub's Website") and search for your song, **which has a tablature on it.**
66 |
67 | ##### Example:
68 |
69 | > https://www.cifraclub.com.br/natiruts/andei-so/
70 |
71 | #### Running the code
72 | Then execute in the terminal, with your url in the url param:
73 |
74 | > node index.js --url=https://www.cifraclub.com.br/natiruts/andei-so/
75 |
76 | #### Uploading to Arduino
77 |
78 | After that a **music.ino** file will be generated, inside the music folder, and you will be able to [upload it to your arduino](https://www.arduino.cc/en/Guide/HomePage) using the Arduino IDE or others.
79 |
80 |
81 | ## Broken Musics and Bugs
82 |
83 | Some music is not working? We have a [thread issue](https://github.com/ThiagoAugustoSM/arduino-tablature/issues/5) open to report bugs in specific musics, report in the issue following the report example, and soon as possible the community will fix it.
84 |
85 | Some bug? You can also open your own issue to report a bug.
86 |
87 | _tip: It is a good idea, when you find a bug, open a issue to report it, and make a pull request with the solution, becoming a contributor of the project_
88 |
89 | ## Contributors
90 | **Thiago Augusto** ([GitHub :octocat:](https://github.com/ThiagoAugustoSM))
91 |
92 | 
93 | **Idealization and coding**
94 |
95 | **Otacilio Maia** ([GitHub :octocat:](https://github.com/OtacilioN))
96 |
97 | 
98 | **Documentation and coding**
99 |
100 |
101 |
102 | **Yourself**
103 |
104 | 
105 |
106 | Become a contributor, fork this repository, make your modifications and submit a pull request. See the complete list of [contributors](https://github.com/ThiagoAugustoSM/arduino-tablature/graphs/contributors).
107 |
108 | ## License
109 |
110 | See the [LICENSE](LICENSE.md) file for license rights and limitations (MIT).
111 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | var express = require('express')
2 | var app = express()
3 |
4 | app.set('view engine', 'pug')
5 | // respond with "hello world" when a GET request is made to the homepage
6 | app.get('/', function (req, res) {
7 | res.render('index', {
8 | title: 'arduino-tablature',
9 | message: 'Arduino Tablature!' })
10 | })
11 |
12 | app.listen(3000, function() {
13 | console.log('Example app listening on port 3000!');
14 | });
15 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # arduino-tablature
2 |
3 | Node.js project that makes a web scraping to get some guitar tablature and transform
4 | it to an Arduino Program compatible with the tone() Function.
5 |
6 | ## About the project
7 |
8 | ### What is a tablature?
9 |
10 | Tablature (or tabulature, or tab for short) is a form of musical notation indicating instrument fingering rather than musical pitches. _- Wikipedia words_
11 |
12 | And it looks like this:
13 |
14 | 
15 |
16 | #### Nice, but what can i do with this project?
17 |
18 | So, with a circuit like that:
19 |
20 | 
21 |
22 | Using this project you can play your favorite songs in your own Arduino.
23 |
24 | ## How to use it (Recommended way)
25 |
26 | First of all, make sure you have [npm and node](https://www.npmjs.com/get-npm) installed.
27 |
28 | ### Installation
29 | Open your terminal and type:
30 |
31 | > sudo npm install -g arduino-tablature
32 |
33 | Now you have the arduino-tablature command available globally
34 |
35 | ### Picking your tablature
36 |
37 | - Go to [CifraClub's WebSite](https://www.cifraclub.com.br "CifraClub's Website") and search for your song, **which has a tablature on it.**
38 |
39 | #### Example:
40 |
41 | > https://www.cifraclub.com.br/natiruts/andei-so/
42 |
43 | ### Running the code
44 | Then execute in the terminal, with your url in the url param:
45 |
46 | > arduino-tablature --url=https://www.cifraclub.com.br/natiruts/andei-so/
47 |
48 | ### Uploading to Arduino
49 |
50 | After that a **music.ino** file will be generated, inside the music folder, and you will be able to [upload it to your arduino](https://www.arduino.cc/en/Guide/HomePage) using the Arduino IDE or others.
51 |
52 | ### Alternative way
53 |
54 | #### Installation
55 |
56 | 1. start [cloning/downloading](https://github.com/ThiagoAugustoSM/arduino-tablature/zipball/master) this repository. _if you download a .zip or .tar.gz file, unzip the file._
57 | 2. In the terminal navigate to the folder, then run:
58 |
59 | > npm install
60 |
61 | After it all the dependencies packages are all set.
62 |
63 | #### Picking your tablature
64 |
65 | - Go to [CifraClub's WebSite](https://www.cifraclub.com.br "CifraClub's Website") and search for your song, **which has a tablature on it.**
66 |
67 | ##### Example:
68 |
69 | > https://www.cifraclub.com.br/natiruts/andei-so/
70 |
71 | #### Running the code
72 | Then execute in the terminal, with your url in the url param:
73 |
74 | > node index.js --url=https://www.cifraclub.com.br/natiruts/andei-so/
75 |
76 | #### Uploading to Arduino
77 |
78 | After that a **music.ino** file will be generated, inside the music folder, and you will be able to [upload it to your arduino](https://www.arduino.cc/en/Guide/HomePage) using the Arduino IDE or others.
79 |
80 |
81 | ## Broken Musics and Bugs
82 |
83 | Some music is not working? We have a [thread issue](https://github.com/ThiagoAugustoSM/arduino-tablature/issues/5) open to report bugs in specific musics, report in the issue following the report example, and soon as possible the community will fix it.
84 |
85 | Some bug? You can also open your own issue to report a bug.
86 |
87 | _tip: It is a good idea, when you find a bug, open a issue to report it, and make a pull request with the solution, becoming a contributor of the project_
88 |
89 | ## Contributors
90 | **Thiago Augusto** ([GitHub](https://github.com/ThiagoAugustoSM))
91 |
92 | 
93 | **Idealization and coding**
94 |
95 | **Otacilio Maia** ([GitHub](https://github.com/OtacilioN))
96 |
97 | 
98 | **Documentation and coding**
99 |
100 |
101 |
102 | **Yourself**
103 |
104 | 
105 |
106 | Become a contributor, fork this repository, make your modifications and submit a pull request. See the complete list of [contributors](https://github.com/ThiagoAugustoSM/arduino-tablature/graphs/contributors).
107 |
108 | ## Disclaimer
109 |
110 | The authors of this project have no association with the Cifras Club. Cifras Club is a registered trademark
111 |
112 | ## License
113 |
114 | See the [LICENSE](LICENSE.md) file for license rights and limitations (MIT).
115 |
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
2 | show_downloads: ["true"]
3 |
--------------------------------------------------------------------------------
/docs/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThiagoAugustoSM/arduino-tablature/c0beaa46e04073820002f733d691107107413320/docs/favicon.ico
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /*
3 | This program makes a web scraping to get some guitar tablature and transform
4 | it to an Arduino Program compatible with the tone() Function
5 |
6 | Git-repository: https://github.com/ThiagoAugustoSM/arduino-tablature
7 | Author: thiagoaugustosm
8 | License: MIT
9 | */
10 |
11 | const request = require('request');
12 | const fs = require('fs');
13 | const args = require('yargs').argv;
14 | const makeFile = require('./src/baseFile.js');
15 | const tablature = require('./src/tablature.js');
16 | const scraper = require('./src/scraper.js');
17 | var mkdirp = require('mkdirp');
18 |
19 | mkdirp('music', function (err) {
20 | if (err) console.error(err);
21 | else console.log('dir music created with success');
22 | });
23 |
24 | var url;
25 |
26 | if(args.url != undefined){
27 | url = args.url;
28 | console.log('requesting from:' + args.url);
29 | // Request to get the html from cifraclub's website
30 | request(url, function(error, response, html){
31 |
32 | if(!error){
33 |
34 | var song = scraper.getSong(url, html);
35 |
36 | var tabInNotes = song.tabs.map(tab => tablature.filterTab(tab, song.capo));
37 |
38 | var arduinoFile = makeFile.generateFile(tabInNotes);
39 |
40 | // Saving file in the same directory
41 | fs.writeFile('music/music.ino', arduinoFile, function (err) {
42 | if (err) throw err;
43 | console.log('Saved!');
44 | });
45 |
46 | }else{
47 | console.log("ERROR");
48 | }
49 | });
50 | }
51 | else{
52 | console.log('You must pass a url in a param, example: --url=https://www.cifraclub.com.br/natiruts/andei-so/');
53 | }
--------------------------------------------------------------------------------
/music/.gitignore:
--------------------------------------------------------------------------------
1 | ### Ignoring Music ###
2 | music/music.ino
3 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "arduino-tablature",
3 | "version": "1.1.0-rc.0",
4 | "description": "A web script to get a guitar tablature and make it into Arduino Tone Function form.",
5 | "main": "index.js",
6 | "bin": {
7 | "arduino-tablature": "./index.js"
8 | },
9 | "dependencies": {
10 | "cheerio": "^1.0.0-rc.2",
11 | "express": "^4.16.2",
12 | "fs": "0.0.1-security",
13 | "mkdirp": "^0.5.1",
14 | "pug": "^2.0.0-rc.4",
15 | "request": "^2.83.0",
16 | "require": "^2.4.20",
17 | "yargs": "^11.0.0"
18 | },
19 | "devDependencies": {
20 | "mocha": "^5.2.0"
21 | },
22 | "scripts": {
23 | "test": "mocha"
24 | },
25 | "repository": {
26 | "type": "git",
27 | "url": "git+https://github.com/ThiagoAugustoSM/arduino-tablature.git"
28 | },
29 | "keywords": [
30 | "arduino",
31 | "tablature",
32 | "guitar"
33 | ],
34 | "author": "thiagoaugustosm",
35 | "contributors": [
36 | {
37 | "name": "Otacilio Maia",
38 | "email": "contato@otaciliomaia.com",
39 | "url": "http://otaciliomaia.com/"
40 | }
41 | ],
42 | "license": "MIT",
43 | "bugs": {
44 | "url": "https://github.com/ThiagoAugustoSM/arduino-tablature/issues"
45 | },
46 | "homepage": "https://thiagoaugustosm.github.io/arduino-tablature/"
47 | }
48 |
--------------------------------------------------------------------------------
/src/baseFile.js:
--------------------------------------------------------------------------------
1 | var exports = module.exports = {};
2 |
3 | exports.generateFile = function(tabs){
4 | var text =
5 | `/*
6 | File Generated by arduino-tablature
7 | Git-repository: https://github.com/ThiagoAugustoSM/arduino-tablature
8 | Author: thiagoaugustosm
9 | License: MIT
10 | */
11 |
12 | // Change to your Buzzer Pin
13 | #define buzzerPin 10
14 | // Change the Pause time in miliseconds
15 | #define PAUSE 100
16 |
17 | /*************************************************
18 | * Public Constants
19 | *************************************************/
20 |
21 | #define NOTE_B0 31
22 | #define NOTE_C1 33
23 | #define NOTE_CS1 35
24 | #define NOTE_D1 37
25 | #define NOTE_DS1 39
26 | #define NOTE_E1 41
27 | #define NOTE_F1 44
28 | #define NOTE_FS1 46
29 | #define NOTE_G1 49
30 | #define NOTE_GS1 52
31 | #define NOTE_A1 55
32 | #define NOTE_AS1 58
33 | #define NOTE_B1 62
34 | #define NOTE_C2 65
35 | #define NOTE_CS2 69
36 | #define NOTE_D2 73
37 | #define NOTE_DS2 78
38 | #define NOTE_E2 82
39 | #define NOTE_F2 87
40 | #define NOTE_FS2 93
41 | #define NOTE_G2 98
42 | #define NOTE_GS2 104
43 | #define NOTE_A2 110
44 | #define NOTE_AS2 117
45 | #define NOTE_B2 123
46 | #define NOTE_C3 131
47 | #define NOTE_CS3 139
48 | #define NOTE_D3 147
49 | #define NOTE_DS3 156
50 | #define NOTE_E3 165
51 | #define NOTE_F3 175
52 | #define NOTE_FS3 185
53 | #define NOTE_G3 196
54 | #define NOTE_GS3 208
55 | #define NOTE_A3 220
56 | #define NOTE_AS3 233
57 | #define NOTE_B3 247
58 | #define NOTE_C4 262
59 | #define NOTE_CS4 277
60 | #define NOTE_D4 294
61 | #define NOTE_DS4 311
62 | #define NOTE_E4 330
63 | #define NOTE_F4 349
64 | #define NOTE_FS4 370
65 | #define NOTE_G4 392
66 | #define NOTE_GS4 415
67 | #define NOTE_A4 440
68 | #define NOTE_AS4 466
69 | #define NOTE_B4 494
70 | #define NOTE_C5 523
71 | #define NOTE_CS5 554
72 | #define NOTE_D5 587
73 | #define NOTE_DS5 622
74 | #define NOTE_E5 659
75 | #define NOTE_F5 698
76 | #define NOTE_FS5 740
77 | #define NOTE_G5 784
78 | #define NOTE_GS5 831
79 | #define NOTE_A5 880
80 | #define NOTE_AS5 932
81 | #define NOTE_B5 988
82 | #define NOTE_C6 1047
83 | #define NOTE_CS6 1109
84 | #define NOTE_D6 1175
85 | #define NOTE_DS6 1245
86 | #define NOTE_E6 1319
87 | #define NOTE_F6 1397
88 | #define NOTE_FS6 1480
89 | #define NOTE_G6 1568
90 | #define NOTE_GS6 1661
91 | #define NOTE_A6 1760
92 | #define NOTE_AS6 1865
93 | #define NOTE_B6 1976
94 | #define NOTE_C7 2093
95 | #define NOTE_CS7 2217
96 | #define NOTE_D7 2349
97 | #define NOTE_DS7 2489
98 | #define NOTE_E7 2637
99 | #define NOTE_F7 2794
100 | #define NOTE_FS7 2960
101 | #define NOTE_G7 3136
102 | #define NOTE_GS7 3322
103 | #define NOTE_A7 3520
104 | #define NOTE_AS7 3729
105 | #define NOTE_B7 3951
106 | #define NOTE_C8 4186
107 | #define NOTE_CS8 4435
108 | #define NOTE_D8 4699
109 | #define NOTE_DS8 4978
110 |
111 | void setup(){
112 | pinMode(buzzerPin, OUTPUT);
113 | }
114 |
115 | void loop(){
116 | `;
117 |
118 |
119 | var numTabs = tabs.length;
120 | var qntStrings = tabs[0].length;
121 | // All the tabs have the same size
122 | var sizeOfTab = tabs[0][0].length;
123 | var hadSound = false;
124 |
125 | var i = 0, j = 0, k = 0;
126 | for(i = 0; i < numTabs; i++){
127 | text += " // " + (i + 1) + " TAB" + '\n';
128 | for(k = 0; k < sizeOfTab; k++){
129 | for(j = 0; j < qntStrings; j++){
130 | if(tabs[i][j][k] != "PAUSE"){
131 | text += " tone(buzzerPin, " + tabs[i][j][k] + ");" + '\n';
132 | hadSound = true;
133 | }
134 | }
135 |
136 | if(hadSound == false){
137 | text += " delay(PAUSE);" + '\n';
138 | }else{
139 | hadSound = false;
140 | }
141 | }
142 | }
143 | text += "}";
144 | console.log(text);
145 | return text;
146 | }
147 |
--------------------------------------------------------------------------------
/src/scraper.js:
--------------------------------------------------------------------------------
1 | var exports = module.exports = {};
2 |
3 | const cheerio = require('cheerio');
4 |
5 | class CifraClubSCraper {
6 | getCapo($){
7 | var capo = $("#cifra_capo").children().contents().text();
8 | if(capo.length > 0){
9 | capo = parseInt(capo.split('ª')[0]);
10 | }else{
11 | capo = 0;
12 | }
13 | return capo;
14 | }
15 |
16 | getTabs($){
17 | let tabs = [];
18 | $(".tablatura").each(function(){
19 | tabs.push($(this).text());
20 | });
21 | return tabs;
22 | }
23 | }
24 |
25 | class EChordsScraper {
26 | getCapo($){
27 | return 0;
28 | }
29 |
30 | getTabs($){
31 | const core = $("#core").text().trim();
32 | const regex = /([Ee][:|](?:.*\|\s?\n){5}.*\|)/gm;
33 | return core.match(regex);
34 | }
35 | }
36 |
37 | function getScraper(url){
38 | if(url.includes('e-chords')){
39 | return new EChordsScraper();
40 | }
41 | return new CifraClubSCraper();
42 | }
43 |
44 | exports.getSong = function(url, html){
45 | var $ = cheerio.load(html);
46 |
47 | var scraper = getScraper(url);
48 | var capo = scraper.getCapo($);
49 | var tabs = scraper.getTabs($);
50 |
51 | return {
52 | capo,
53 | tabs
54 | };
55 | };
--------------------------------------------------------------------------------
/src/tablature.js:
--------------------------------------------------------------------------------
1 | var exports = module.exports = {};
2 |
3 | var typesOfPause = ['-', 'h', '/', 'p'];
4 | var typesOfNotes = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
5 | var typesOfBlockLimits = ['|'];
6 | var notes = [
7 | 'NOTE_C', 'NOTE_CS', 'NOTE_D', 'NOTE_DS', 'NOTE_E',
8 | 'NOTE_F', 'NOTE_FS', 'NOTE_G', 'NOTE_GS', 'NOTE_A',
9 | 'NOTE_AS', 'NOTE_B']
10 | /*
11 | In a normal acoustic guitar tuning the notes of the strings are in this sequence:
12 | From bottom to top: E4, B3, G3, D3, A2, E2
13 |
14 | Example:
15 |
16 | E4|---------0-------0----------0-------------|
17 | B3|-----1-----1------------6-----6-----6-----|
18 | G3|---2---2-----2--------5---5-----5---------|
19 | D3|-3-------------3----0-------------0-------|
20 | A2|------------------------------------------|
21 | E2|------------------------------------------|
22 |
23 | And the sequences would be: (related to the guitar's arm)
24 |
25 | E4 F4 F#4 G4 Ab4 A4 Bb4 B4 C5 C#5 D5 Eb5 E5 F5 F#5 G5 Ab5 A5 Bb5 B5 C6 C#6 D6
26 | B3 C4 C#4 D4 Eb4 E4 F4 F#4 G4 Ab4 A4 Bb4 B4 C5 C#5 D5 Eb5 E5 F5 F#5 G5 Ab5 A5
27 | G3 Ab3 A3 Bb3 B3 C4 C#4 D4 Eb4 E4 F4 F#4 G4 Ab4 A4 Bb4 B4 C5 C#5 D5 Eb5 E5 F5
28 | D3 Eb3 E3 F3 F#3 G3 Ab3 A3 Bb3 B3 C4 C#4 D4 Eb4 E4 F4 F#4 G4 Ab4 A4 Bb4 B4 C5
29 | A2 Bb2 B2 C3 C#3 D3 Eb3 E3 F3 F#3 G3 Ab3 A3 Bb3 B3 C4 C#4 D4 Eb4 E4 F4 F#4 G4
30 | E2 F2 F#2 G2 Ab2 A2 Bb2 B2 C3 C#3 D3 Eb3 E3 F3 F#3 G3 Ab3 A3 Bb3 B3 C4 C#4 D4
31 |
32 | */
33 |
34 | function isNote(char){
35 | if(typesOfNotes.indexOf(char) !== -1){
36 | return true;
37 | }
38 | return false;
39 | }
40 |
41 | function isNumber(char){
42 | if(char.charCodeAt(0) >= "0".charCodeAt(0) && char.charCodeAt(0) <= "9".charCodeAt(0)){
43 | return true;
44 | }
45 | return false;
46 | }
47 |
48 | function isPause(char){
49 | if(typesOfPause.indexOf(char) !== -1){
50 | return true;
51 | }
52 | return false;
53 | }
54 |
55 | function isBlockLimit(char){
56 | if(typesOfBlockLimits.indexOf(char) !== -1){
57 | return true;
58 | }
59 | return false;
60 | }
61 |
62 | function toNote(mainNote, char){
63 | if(isPause(char)){
64 | return "PAUSE";
65 | }
66 |
67 | // The main ideia is to run through all the scale of string
68 | // Going from G3 to C4 for Example
69 | // But running in the notes array as a circular array
70 |
71 | var tuning = parseInt(mainNote.substring(mainNote.length - 1, mainNote.length));
72 | var frets = parseInt(char);
73 |
74 | var i = 0;
75 | for(i = notes.indexOf(mainNote.substring(0, mainNote.length - 1));
76 | frets > 0;
77 | i = (i + 1) % (notes.length)){
78 | if(i == 0){
79 | tuning++;
80 | }
81 | frets--;
82 |
83 | }
84 | return notes[i] + tuning;
85 | }
86 |
87 | exports.filterTab = function (tab, capo){
88 |
89 | var tabInForm = [];
90 | var state = 0;
91 | var actualString = 0; // Counting from bottom to top
92 | var actualMainNote = "";
93 |
94 | // Running through every char in the tab function
95 | tab = tab.split('');
96 | tab.forEach(function(char, index){
97 |
98 | // Working in a state machine to filter the actual data
99 | // State 0 - Getting the actual tuning of the string
100 | if(state === 0 && isNote(char)){
101 |
102 | if(char == 'E' && actualString == 0){
103 | actualMainNote = "NOTE_E4";
104 | }else if(char == 'B'){
105 | actualMainNote = "NOTE_B3";
106 | }else if(char == 'G'){
107 | actualMainNote = "NOTE_G3";
108 | }else if(char == 'D'){
109 | actualMainNote = "NOTE_D3";
110 | }else if(char == 'A'){
111 | actualMainNote = "NOTE_A2";
112 | }else if(char == 'E'){
113 | actualMainNote = "NOTE_E2";
114 | }
115 | // If there is capo it will increase the tuning
116 | actualMainNote = toNote(actualMainNote, capo);
117 |
118 | tabInForm.push([])
119 | state = 1;
120 | }else if(state === 1 && (isPause(char) || isNumber(char))){
121 |
122 | // Some tab use the 10th fret or more
123 | if(isNumber(tab[index]) && isNumber(tab[index + 1])){
124 | tabInForm[actualString].push(toNote(actualMainNote, char + tab[index + 1]));
125 | }else if(isNumber(tab[index - 1])){
126 | // This number was already computed in the last element
127 | // So it is now considered a pause
128 | tabInForm[actualString].push("PAUSE");
129 | }else{
130 | // A number appeared alone in the fret
131 | tabInForm[actualString].push(toNote(actualMainNote, char));
132 | }
133 |
134 | // Works because the first block limit after the Note won't be read
135 | if(isBlockLimit(tab[index + 1])){
136 | state = 2;
137 | }
138 | }else if(state === 2){
139 | ++actualString;
140 | state = 0;
141 | }
142 | });
143 | return tabInForm;
144 | }
145 |
--------------------------------------------------------------------------------
/test/e-chords.scraper.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert');
2 | const scraper = require('../src/scraper.js');
3 |
4 | const tab = `E|-------|-0-----------------3----0---3-|-------|
5 | B|-1---3-|-------3---1----3-------------|---3---|
6 | G|-------|------------------------------|-------|
7 | D|-------|------------------------------|-------|
8 | A|-------|-0----------------------------|-------|
9 | E|-------|----------------3-------------|---3---|`;
10 |
11 | function eChordsHtml(content){
12 | return `
13 |
14 | ${content} 15 | 16 |17 | `; 18 | } 19 | 20 | describe('scraper', function() { 21 | 22 | describe('e-chords', function() { 23 | 24 | it('should get one tab', function() { 25 | const html = eChordsHtml(tab); 26 | 27 | let song = scraper.getSong('e-chords', html); 28 | assert.equal(song.tabs.length, 1); 29 | assert.equal(song.tabs[0], tab); 30 | }); 31 | 32 | it('should get two tabs separated by new line', function() { 33 | const html = eChordsHtml(`${tab}\n${tab}`); 34 | 35 | let song = scraper.getSong('e-chords', html); 36 | assert.equal(song.tabs.length, 2); 37 | assert.equal(song.tabs[0], tab); 38 | assert.equal(song.tabs[1], tab); 39 | }); 40 | 41 | it('should get two tabs separated by html tags', function() { 42 | const html = eChordsHtml(`${tab}\n2ª parte\n${tab}`); 43 | 44 | let song = scraper.getSong('e-chords', html); 45 | assert.equal(song.tabs.length, 2); 46 | assert.equal(song.tabs[0], tab); 47 | assert.equal(song.tabs[1], tab); 48 | }); 49 | 50 | it('should get one tab that starts with e instead of E', function() { 51 | const modifiedTab = `e${tab.substring(1)}`; 52 | const html = eChordsHtml(modifiedTab); 53 | 54 | let song = scraper.getSong('e-chords', html); 55 | assert.equal(song.tabs.length, 1); 56 | assert.equal(song.tabs[0], modifiedTab); 57 | }); 58 | 59 | it('should get one tab that uses : at the beginning', function() { 60 | const colonTab = `e:-7---------------7---------------|-----------9---------------------| 61 | B:-7---------7-------------7---7---|-------7-------7-----------------| 62 | G:-7-----7-------7---------7---9---|-----9-------9-------------------| 63 | D:-9---9---9---9-------------------|-8---------------8---------------| 64 | A:-9-------------------------------|---------9-----------------------| 65 | E:-7-------------------------------|---------------------------------|`; 66 | const html = eChordsHtml(colonTab); 67 | 68 | let song = scraper.getSong('e-chords', html); 69 | assert.equal(song.tabs.length, 1); 70 | assert.equal(song.tabs[0], colonTab); 71 | }); 72 | 73 | }); 74 | 75 | }); -------------------------------------------------------------------------------- /views/index.pug: -------------------------------------------------------------------------------- 1 | html 2 | head 3 | title= title 4 | body 5 | h1= message 6 | input 7 | button Submit 8 | --------------------------------------------------------------------------------