├── .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 | ![](https://i.imgur.com/5tiTV8J.png) 15 | 16 | #### Nice, but what can i do with this project? 17 | 18 | So, with a circuit like that: 19 | 20 | ![](https://i.imgur.com/wP9z0lu.png) 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 | ![](https://github.com/ThiagoAugustoSM.png?size=230)
93 | **Idealization and coding** 94 | 95 | **Otacilio Maia** ([GitHub :octocat:](https://github.com/OtacilioN)) 96 |
97 | ![](https://github.com/OtacilioN.png?size=230)
98 | **Documentation and coding** 99 | 100 |
101 | 102 | **Yourself** 103 | 104 | ![](https://i.imgur.com/G1mfFQT.png) 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 | ![](https://i.imgur.com/5tiTV8J.png) 15 | 16 | #### Nice, but what can i do with this project? 17 | 18 | So, with a circuit like that: 19 | 20 | ![](https://i.imgur.com/wP9z0lu.png) 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 | ![](https://github.com/ThiagoAugustoSM.png?size=230)
93 | **Idealization and coding** 94 | 95 | **Otacilio Maia** ([GitHub](https://github.com/OtacilioN)) 96 |
97 | ![](https://github.com/OtacilioN.png?size=230)
98 | **Documentation and coding** 99 | 100 |
101 | 102 | **Yourself** 103 | 104 | ![](https://i.imgur.com/G1mfFQT.png) 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 | --------------------------------------------------------------------------------