├── .gitignore
├── README.md
├── assets
└── style.css
├── webpack.config.babel.js
├── dist
├── index.js
├── index.umd.min.js
├── index.umd.js
├── index.umd.js.map
└── index.umd.min.js.map
├── src
└── index.js
├── index.html
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .idea
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Play RTTTL files online
2 |
3 | [Play RTTTL Online](https://adamonsoon.github.io/rtttl-play/)
4 |
5 | For RTTTL parsing use [rtttl-parse](https://github.com/adamonsoon/rtttl-parse)
6 |
--------------------------------------------------------------------------------
/assets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color:#f5f5f5;
3 | }
4 |
5 | h1 {
6 | font-weight:bold;
7 | text-align:center;
8 | }
9 |
10 | textarea {
11 | width:100%;
12 | border:0;
13 | margin:0 auto;
14 | padding:15px;
15 | font-size:20px;
16 | }
17 |
18 | .rttl-parse {
19 | margin-top: 20px;
20 | }
--------------------------------------------------------------------------------
/webpack.config.babel.js:
--------------------------------------------------------------------------------
1 | import {join} from 'path'
2 |
3 | const include = join(__dirname, 'src')
4 |
5 | export default {
6 | entry: './src/index',
7 | output: {
8 | path: join(__dirname, 'dist'),
9 | libraryTarget: 'umd',
10 | library: 'rtttlPlay',
11 | },
12 | devtool: 'source-map',
13 | module: {
14 | loaders: [
15 | {test: /\.js$/, loader: 'babel-loader', include},
16 | {test: /\.json$/, 'loader': 'json-loader', include},
17 | ]
18 | }
19 | }
20 | 0
21 | 0
22 |
--------------------------------------------------------------------------------
/dist/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var rtttlParse = require('rtttl-parse');
4 |
5 | module.exports = {
6 | play: play,
7 | stop: stop
8 | };
9 |
10 | var shouldStop = false;
11 |
12 | function play(rtttl) {
13 |
14 | try {
15 | var parsedRtttl = rtttlParse.parse(rtttl);
16 | var audioCtx = new (AudioContext || webkitAudioContext)();
17 | _playMelody(parsedRtttl.melody, audioCtx);
18 | } catch (err) {
19 | alert(err);
20 | }
21 | }
22 |
23 | function stop() {
24 | shouldStop = true;
25 | }
26 |
27 | function _playMelody(melody, audioCtx) {
28 |
29 | if (shouldStop) {
30 | shouldStop = false;
31 | return;
32 | }
33 |
34 | var osc = audioCtx.createOscillator();
35 | osc.type = 'triangle';
36 | osc.start(0);
37 |
38 | if (melody.length === 0) {
39 | return;
40 | }
41 |
42 | var note = melody[0];
43 |
44 | osc.frequency.value = note.frequency;
45 | osc.connect(audioCtx.destination);
46 |
47 | setTimeout(function () {
48 | osc.disconnect(audioCtx.destination);
49 | _playMelody(melody.slice(1), audioCtx, osc);
50 | }, note.duration);
51 | }
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | const rtttlParse = require('rtttl-parse');
2 |
3 | module.exports = {
4 | play,
5 | stop
6 | };
7 |
8 | let shouldStop = false;
9 |
10 | function play(rtttl) {
11 |
12 | try {
13 | const parsedRtttl = rtttlParse.parse(rtttl);
14 | const audioCtx = new (AudioContext || webkitAudioContext)();
15 | _playMelody(parsedRtttl.melody, audioCtx);
16 | } catch(err) {
17 | alert(err);
18 | }
19 |
20 | }
21 |
22 | function stop() {
23 | shouldStop = true;
24 | }
25 |
26 | function _playMelody(melody, audioCtx) {
27 |
28 | if (shouldStop) {
29 | shouldStop = false;
30 | return;
31 | }
32 |
33 | const osc = audioCtx.createOscillator();
34 | osc.type = 'triangle';
35 | osc.start(0);
36 |
37 | if (melody.length === 0) {
38 | return;
39 | }
40 |
41 | const note = melody[0];
42 |
43 | osc.frequency.value = note.frequency;
44 | osc.connect(audioCtx.destination);
45 |
46 | setTimeout(() => {
47 | osc.disconnect(audioCtx.destination);
48 | _playMelody(melody.slice(1), audioCtx, osc);
49 | }, note.duration);
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Play RTTTL Online
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
18 |
19 |
20 |
21 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rtttl-play",
3 | "version": "1.0.0",
4 | "description": "Play RTTTL files online",
5 | "main": "src/index.js",
6 | "scripts": {
7 | "commit": "git-cz",
8 | "check-coverage": "istanbul check-coverage --statements 100 --branches 100 --functions 100 --lines 100",
9 | "report-coverage": "cat ./coverage/lcov.info | codecov",
10 | "build": "npm-run-all --parallel build:*",
11 | "build:main": "babel --out-dir dist --ignore *.test.js src",
12 | "build:umd": "webpack --output-filename index.umd.js",
13 | "build:umd.min": "webpack --output-filename index.umd.min.js -p",
14 | "prebuild": "rimraf dist",
15 | "semantic-release": "semantic-release pre && npm publish && semantic-release post"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "git+https://github.com/adamonsoon/rtttl-play.git"
20 | },
21 | "keywords": [
22 | "rtttl",
23 | "nokia"
24 | ],
25 | "author": "Adam Rahwane (https://github.com/adamonsoon)",
26 | "license": "MIT",
27 | "bugs": {
28 | "url": "https://github.com/adamonsoon/rtttl-play/issues"
29 | },
30 | "homepage": "https://github.com/adamonsoon/rtttl-play#readme",
31 | "devDependencies": {
32 | "babel-cli": "6.24.0",
33 | "babel-loader": "6.4.1",
34 | "babel-preset-es2015": "6.24.0",
35 | "babel-preset-stage-2": "6.22.0",
36 | "chai": "3.5.0",
37 | "istanbul": "0.4.5",
38 | "json-loader": "0.5.4",
39 | "mocha": "3.2.0",
40 | "npm-run-all": "4.0.2",
41 | "rimraf": "2.6.1",
42 | "sinon": "2.1.0",
43 | "webpack": "2.3.2"
44 | },
45 | "czConfig": {
46 | "path": "node_modules/cz-conventional-changelog"
47 | },
48 | "config": {
49 | "ghooks": {
50 | "pre-commit": "npm run test:single && npm run check-coverage"
51 | }
52 | },
53 | "babel": {
54 | "presets": [
55 | "es2015",
56 | "stage-2"
57 | ]
58 | },
59 | "dependencies": {
60 | "rtttl-parse": "1.3.1"
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/dist/index.umd.min.js:
--------------------------------------------------------------------------------
1 | !function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.rtttlPlay=n():t.rtttlPlay=n()}(this,function(){return function(t){function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var e={};return n.m=t,n.c=e,n.i=function(t){return t},n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:r})},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},n.p="",n(n.s=1)}([function(t,n,e){"use strict";function r(t){var n=t.split(":");if(3!==n.length)throw new Error("Invalid RTTTL file.");var e=o(n[0]),r=a(n[1]);return{name:e,defaults:r,melody:u(n[2],r)}}function o(t){return t.length>10&&console.warn("Tune name should not exceed 10 characters."),t?t:"Unknown"}function a(t){var n=t.split(","),e=n.map(function(t){if(""===t)return{};var n=t.split("=");if(2!==n.length)throw new Error("Invalid setting "+t);var e=n[0],r=n[1],o=["1","2","4","8","16","32"],a=["4","5","6","7"],i=["25","28","31","35","40","45","50","56","63","70","80","90","100","112","125","140","160","180","200","225","250","285","320","355","400","450","500","565","635","715","800","900"];switch(e){case"d":if(o.indexOf(r)!==-1)return{duration:r};throw new Error("Invalid duration "+r);case"o":return a.indexOf(r)===-1&&console.warn("Invalid octave "+r),{octave:r};case"b":return i.indexOf(r)===-1&&console.warn("Invalid BPM "+r),{bpm:r}}}),r=i({},e),o={duration:"4",octave:"6",bpm:"63"};return Object.assign(o,r)}function i(t,n){return 0===n.length?t:i(Object.assign(t,n[0]),n.slice(1))}function u(t,n){var e=t.split(","),r=6e4/parseInt(n.bpm);return e.map(function(t){var e=t.match(/(1|2|4|8|16|32|64)?((?:[a-g]|h|p)#?){1}(\.?)(4|5|6|7)?/),o=e[1]||parseInt(n.duration),a="h"===e[2]?"b":e[2],i="."===e[3],u=e[4]||parseInt(n.octave);return{note:a,duration:s(r,parseFloat(o),i),frequency:c(a,u)}})}function c(t,n){if("p"===t)return 0;var e=Math.pow(2,1/12),r=f(t,n),o=261.63*Math.pow(e,r);return Math.round(10*o)/10}function f(t,n){var e=["c","c#","d","d#","e","f","f#","g","g#","a","a#","b"],r=12*(n-4);return e.indexOf(t)+r}function s(t,n,e){var r=4*t/n;return r+(e?r/2:0)}t.exports={parse:r,getName:o,getDefaults:a,getData:u}},function(t,n,e){"use strict";function r(t){try{var n=i.parse(t),e=new(AudioContext||webkitAudioContext);a(n.melody,e)}catch(t){alert(t)}}function o(){u=!0}function a(t,n){if(u)return void(u=!1);var e=n.createOscillator();if(e.type="triangle",e.start(0),0!==t.length){var r=t[0];e.frequency.value=r.frequency,e.connect(n.destination),setTimeout(function(){e.disconnect(n.destination),a(t.slice(1),n,e)},r.duration)}}var i=e(0);t.exports={play:r,stop:o};var u=!1}])});
2 | //# sourceMappingURL=index.umd.min.js.map
--------------------------------------------------------------------------------
/dist/index.umd.js:
--------------------------------------------------------------------------------
1 | (function webpackUniversalModuleDefinition(root, factory) {
2 | if(typeof exports === 'object' && typeof module === 'object')
3 | module.exports = factory();
4 | else if(typeof define === 'function' && define.amd)
5 | define([], factory);
6 | else if(typeof exports === 'object')
7 | exports["rtttlPlay"] = factory();
8 | else
9 | root["rtttlPlay"] = factory();
10 | })(this, function() {
11 | return /******/ (function(modules) { // webpackBootstrap
12 | /******/ // The module cache
13 | /******/ var installedModules = {};
14 | /******/
15 | /******/ // The require function
16 | /******/ function __webpack_require__(moduleId) {
17 | /******/
18 | /******/ // Check if module is in cache
19 | /******/ if(installedModules[moduleId])
20 | /******/ return installedModules[moduleId].exports;
21 | /******/
22 | /******/ // Create a new module (and put it into the cache)
23 | /******/ var module = installedModules[moduleId] = {
24 | /******/ i: moduleId,
25 | /******/ l: false,
26 | /******/ exports: {}
27 | /******/ };
28 | /******/
29 | /******/ // Execute the module function
30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
31 | /******/
32 | /******/ // Flag the module as loaded
33 | /******/ module.l = true;
34 | /******/
35 | /******/ // Return the exports of the module
36 | /******/ return module.exports;
37 | /******/ }
38 | /******/
39 | /******/
40 | /******/ // expose the modules object (__webpack_modules__)
41 | /******/ __webpack_require__.m = modules;
42 | /******/
43 | /******/ // expose the module cache
44 | /******/ __webpack_require__.c = installedModules;
45 | /******/
46 | /******/ // identity function for calling harmony imports with the correct context
47 | /******/ __webpack_require__.i = function(value) { return value; };
48 | /******/
49 | /******/ // define getter function for harmony exports
50 | /******/ __webpack_require__.d = function(exports, name, getter) {
51 | /******/ if(!__webpack_require__.o(exports, name)) {
52 | /******/ Object.defineProperty(exports, name, {
53 | /******/ configurable: false,
54 | /******/ enumerable: true,
55 | /******/ get: getter
56 | /******/ });
57 | /******/ }
58 | /******/ };
59 | /******/
60 | /******/ // getDefaultExport function for compatibility with non-harmony modules
61 | /******/ __webpack_require__.n = function(module) {
62 | /******/ var getter = module && module.__esModule ?
63 | /******/ function getDefault() { return module['default']; } :
64 | /******/ function getModuleExports() { return module; };
65 | /******/ __webpack_require__.d(getter, 'a', getter);
66 | /******/ return getter;
67 | /******/ };
68 | /******/
69 | /******/ // Object.prototype.hasOwnProperty.call
70 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
71 | /******/
72 | /******/ // __webpack_public_path__
73 | /******/ __webpack_require__.p = "";
74 | /******/
75 | /******/ // Load entry module and return exports
76 | /******/ return __webpack_require__(__webpack_require__.s = 1);
77 | /******/ })
78 | /************************************************************************/
79 | /******/ ([
80 | /* 0 */
81 | /***/ (function(module, exports, __webpack_require__) {
82 |
83 | "use strict";
84 |
85 |
86 | module.exports = {
87 | parse: parse,
88 | getName: getName,
89 | getDefaults: getDefaults,
90 | getData: getData
91 | };
92 |
93 | /**
94 | * Parse RTTTL
95 | *
96 | * @param {string} rtttl - RTTTL String
97 | * @returns {object} - An object specifying frequency and duration for each note
98 | */
99 | function parse(rtttl) {
100 |
101 | var REQUIRED_SECTIONS_NUM = 3;
102 | var SECTIONS = rtttl.split(':');
103 |
104 | if (SECTIONS.length !== REQUIRED_SECTIONS_NUM) {
105 | throw new Error('Invalid RTTTL file.');
106 | }
107 |
108 | var NAME = getName(SECTIONS[0]);
109 | var DEFAULTS = getDefaults(SECTIONS[1]);
110 | var MELODY = getData(SECTIONS[2], DEFAULTS);
111 |
112 | return {
113 | name: NAME,
114 | defaults: DEFAULTS,
115 | melody: MELODY
116 | };
117 | }
118 |
119 | /**
120 | * Get ring tone name
121 | *
122 | * @param {string} name
123 | * @returns {string}
124 | */
125 | function getName(name) {
126 |
127 | var MAX_LENGTH = 10;
128 |
129 | if (name.length > MAX_LENGTH) {
130 | console.warn('Tune name should not exceed 10 characters.');
131 | }
132 |
133 | if (!name) {
134 | return 'Unknown';
135 | }
136 |
137 | return name;
138 | }
139 |
140 | /**
141 | * Get duration, octave and BPM
142 | *
143 | * @param {string} defaults
144 | * @returns {object}
145 | */
146 | function getDefaults(defaults) {
147 |
148 | var VALUES = defaults.split(',');
149 |
150 | var VALUES_ARR = VALUES.map(function (value) {
151 |
152 | if (value === '') {
153 | return {};
154 | }
155 |
156 | var KEY_VAL = value.split('=');
157 |
158 | if (KEY_VAL.length !== 2) {
159 | throw new Error('Invalid setting ' + value);
160 | }
161 |
162 | var KEY = KEY_VAL[0];
163 | var VAL = KEY_VAL[1];
164 |
165 | var ALLOWED_DURATION = ['1', '2', '4', '8', '16', '32'];
166 | var ALLOWED_OCTAVE = ['4', '5', '6', '7'];
167 | var ALLOWED_BPM = ['25', '28', '31', '35', '40', '45', '50', '56', '63', '70', '80', '90', '100', '112', '125', '140', '160', '180', '200', '225', '250', '285', '320', '355', '400', '450', '500', '565', '635', '715', '800', '900'];
168 |
169 | switch (KEY) {
170 | case 'd':
171 | if (ALLOWED_DURATION.indexOf(VAL) !== -1) {
172 | return { duration: VAL };
173 | } else {
174 | throw new Error('Invalid duration ' + VAL);
175 | }
176 | case 'o':
177 | if (ALLOWED_OCTAVE.indexOf(VAL) === -1) {
178 | console.warn('Invalid octave ' + VAL);
179 | }
180 | return { octave: VAL };
181 | case 'b':
182 | if (ALLOWED_BPM.indexOf(VAL) === -1) {
183 | console.warn('Invalid BPM ' + VAL);
184 | }
185 | return { bpm: VAL };
186 | }
187 | });
188 |
189 | var VALUES_OBJ = _toObject({}, VALUES_ARR);
190 |
191 | var DEFAULT_VALUES = {
192 | duration: '4',
193 | octave: '6',
194 | bpm: '63'
195 | };
196 |
197 | return Object.assign(DEFAULT_VALUES, VALUES_OBJ);
198 | }
199 |
200 | /**
201 | * Convert an array of objects into an object
202 | *
203 | * @param {object} obj
204 | * @param {Array} arr
205 | * @returns {object}
206 | * @private
207 | */
208 | function _toObject(obj, arr) {
209 |
210 | if (arr.length === 0) {
211 | return obj;
212 | }
213 |
214 | var newObj = Object.assign(obj, arr[0]);
215 |
216 | return _toObject(newObj, arr.slice(1));
217 | }
218 |
219 | /**
220 | * Get the parsed melody data
221 | *
222 | * @param {string} melody
223 | * @param {object} defaults
224 | * @returns {Array}
225 | */
226 | function getData(melody, defaults) {
227 |
228 | var NOTES = melody.split(',');
229 | var BEAT_EVERY = 60000 / parseInt(defaults.bpm);
230 |
231 | return NOTES.map(function (note) {
232 |
233 | var NOTE_REGEX = /(1|2|4|8|16|32|64)?((?:[a-g]|h|p)#?){1}(\.?)(4|5|6|7)?/;
234 | var NOTE_PARTS = note.match(NOTE_REGEX);
235 |
236 | var NOTE_DURATION = NOTE_PARTS[1] || parseInt(defaults.duration);
237 | var NOTE = NOTE_PARTS[2] === 'h' ? 'b' : NOTE_PARTS[2];
238 | var NOTE_DOTTED = NOTE_PARTS[3] === '.';
239 | var NOTE_OCTAVE = NOTE_PARTS[4] || parseInt(defaults.octave);
240 |
241 | return {
242 | note: NOTE,
243 | duration: _calculateDuration(BEAT_EVERY, parseFloat(NOTE_DURATION), NOTE_DOTTED),
244 | frequency: _calculateFrequency(NOTE, NOTE_OCTAVE)
245 | };
246 | });
247 | }
248 |
249 | /**
250 | * Calculate the frequency of a note
251 | *
252 | * @param {string} note
253 | * @param {number} octave
254 | * @returns {number}
255 | * @private
256 | */
257 | function _calculateFrequency(note, octave) {
258 |
259 | if (note === 'p') {
260 | return 0;
261 | }
262 |
263 | var C4 = 261.63;
264 | var TWELFTH_ROOT = Math.pow(2, 1 / 12);
265 | var N = _calculateSemitonesFromC4(note, octave);
266 | var FREQUENCY = C4 * Math.pow(TWELFTH_ROOT, N);
267 |
268 | return Math.round(FREQUENCY * 1e1) / 1e1;
269 | }
270 |
271 | function _calculateSemitonesFromC4(note, octave) {
272 |
273 | var NOTE_ORDER = ['c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#', 'a', 'a#', 'b'];
274 | var MIDDLE_OCTAVE = 4;
275 | var SEMITONES_IN_OCTAVE = 12;
276 |
277 | var OCTAVE_JUMP = (octave - MIDDLE_OCTAVE) * SEMITONES_IN_OCTAVE;
278 |
279 | return NOTE_ORDER.indexOf(note) + OCTAVE_JUMP;
280 | }
281 |
282 | /**
283 | * Calculate the duration a note should be played
284 | *
285 | * @param {number} beatEvery
286 | * @param {number} noteDuration
287 | * @param {boolean} isDotted
288 | * @returns {number}
289 | * @private
290 | */
291 | function _calculateDuration(beatEvery, noteDuration, isDotted) {
292 | var DURATION = beatEvery * 4 / noteDuration;
293 | var PROLONGED = isDotted ? DURATION / 2 : 0;
294 | return DURATION + PROLONGED;
295 | }
296 |
297 | /***/ }),
298 | /* 1 */
299 | /***/ (function(module, exports, __webpack_require__) {
300 |
301 | "use strict";
302 |
303 |
304 | var rtttlParse = __webpack_require__(0);
305 |
306 | module.exports = {
307 | play: play,
308 | stop: stop
309 | };
310 |
311 | var shouldStop = false;
312 |
313 | function play(rtttl) {
314 |
315 | try {
316 | var parsedRtttl = rtttlParse.parse(rtttl);
317 | var audioCtx = new (AudioContext || webkitAudioContext)();
318 | _playMelody(parsedRtttl.melody, audioCtx);
319 | } catch (err) {
320 | alert(err);
321 | }
322 | }
323 |
324 | function stop() {
325 | shouldStop = true;
326 | }
327 |
328 | function _playMelody(melody, audioCtx) {
329 |
330 | if (shouldStop) {
331 | shouldStop = false;
332 | return;
333 | }
334 |
335 | var osc = audioCtx.createOscillator();
336 | osc.type = 'triangle';
337 | osc.start(0);
338 |
339 | if (melody.length === 0) {
340 | return;
341 | }
342 |
343 | var note = melody[0];
344 |
345 | osc.frequency.value = note.frequency;
346 | osc.connect(audioCtx.destination);
347 |
348 | setTimeout(function () {
349 | osc.disconnect(audioCtx.destination);
350 | _playMelody(melody.slice(1), audioCtx, osc);
351 | }, note.duration);
352 | }
353 |
354 | /***/ })
355 | /******/ ]);
356 | });
357 | //# sourceMappingURL=index.umd.js.map
--------------------------------------------------------------------------------
/dist/index.umd.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///webpack/bootstrap 616c6df84e2e399f034b","webpack:///./~/rtttl-parse/dist/index.js","webpack:///./src/index.js"],"names":["rtttlParse","require","module","exports","play","stop","shouldStop","rtttl","parsedRtttl","parse","audioCtx","AudioContext","webkitAudioContext","_playMelody","melody","err","alert","osc","createOscillator","type","start","length","note","frequency","value","connect","destination","setTimeout","disconnect","slice","duration"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;ACVA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA,mDAA2C,cAAc;;AAEzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;AChEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,aAAa,OAAO;AACpB;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,aAAa;AACb;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,aAAa;AACb;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,kBAAkB;AAClB,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB;AACA;AACA;AACA;AACA,gBAAgB;AAChB;AACA,GAAG;;AAEH,+BAA+B;;AAE/B;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,MAAM;AACjB,aAAa;AACb;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa;AACb;AACA;;AAEA;AACA;;AAEA;;AAEA,2DAA2D,EAAE;AAC7D;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa;AACb;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,QAAQ;AACnB,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA,C;;;;;;;;;ACnNA,IAAMA,aAAa,mBAAAC,CAAQ,CAAR,CAAnB;;AAEAC,OAAOC,OAAP,GAAiB;AACfC,YADe;AAEfC;AAFe,CAAjB;;AAKA,IAAIC,aAAa,KAAjB;;AAEA,SAASF,IAAT,CAAcG,KAAd,EAAqB;;AAEnB,MAAI;AACF,QAAMC,cAAcR,WAAWS,KAAX,CAAiBF,KAAjB,CAApB;AACA,QAAMG,WAAc,KAAKC,gBAAgBC,kBAArB,GAApB;AACAC,gBAAYL,YAAYM,MAAxB,EAAgCJ,QAAhC;AACD,GAJD,CAIE,OAAMK,GAAN,EAAW;AACXC,UAAMD,GAAN;AACD;AAEF;;AAED,SAASV,IAAT,GAAgB;AACdC,eAAa,IAAb;AACD;;AAED,SAASO,WAAT,CAAqBC,MAArB,EAA6BJ,QAA7B,EAAuC;;AAErC,MAAIJ,UAAJ,EAAgB;AACdA,iBAAa,KAAb;AACA;AACD;;AAED,MAAMW,MAAMP,SAASQ,gBAAT,EAAZ;AACMD,MAAIE,IAAJ,GAAW,UAAX;AACAF,MAAIG,KAAJ,CAAU,CAAV;;AAEN,MAAIN,OAAOO,MAAP,KAAkB,CAAtB,EAAyB;AACvB;AACD;;AAED,MAAMC,OAAOR,OAAO,CAAP,CAAb;;AAEAG,MAAIM,SAAJ,CAAcC,KAAd,GAAsBF,KAAKC,SAA3B;AACAN,MAAIQ,OAAJ,CAAYf,SAASgB,WAArB;;AAEAC,aAAW,YAAM;AACfV,QAAIW,UAAJ,CAAelB,SAASgB,WAAxB;AACAb,gBAAYC,OAAOe,KAAP,CAAa,CAAb,CAAZ,EAA6BnB,QAA7B,EAAuCO,GAAvC;AACD,GAHD,EAGGK,KAAKQ,QAHR;AAKD,C","file":"index.umd.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"rtttlPlay\"] = factory();\n\telse\n\t\troot[\"rtttlPlay\"] = factory();\n})(this, function() {\nreturn \n\n\n// WEBPACK FOOTER //\n// webpack/universalModuleDefinition"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 1);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 616c6df84e2e399f034b","\"use strict\";\n\nmodule.exports = {\n parse: parse,\n getName: getName,\n getDefaults: getDefaults,\n getData: getData\n};\n\n/**\n * Parse RTTTL\n *\n * @param {string} rtttl - RTTTL String\n * @returns {object} - An object specifying frequency and duration for each note\n */\nfunction parse(rtttl) {\n\n var REQUIRED_SECTIONS_NUM = 3;\n var SECTIONS = rtttl.split(':');\n\n if (SECTIONS.length !== REQUIRED_SECTIONS_NUM) {\n throw new Error('Invalid RTTTL file.');\n }\n\n var NAME = getName(SECTIONS[0]);\n var DEFAULTS = getDefaults(SECTIONS[1]);\n var MELODY = getData(SECTIONS[2], DEFAULTS);\n\n return {\n name: NAME,\n defaults: DEFAULTS,\n melody: MELODY\n };\n}\n\n/**\n * Get ring tone name\n *\n * @param {string} name\n * @returns {string}\n */\nfunction getName(name) {\n\n var MAX_LENGTH = 10;\n\n if (name.length > MAX_LENGTH) {\n console.warn('Tune name should not exceed 10 characters.');\n }\n\n if (!name) {\n return 'Unknown';\n }\n\n return name;\n}\n\n/**\n * Get duration, octave and BPM\n *\n * @param {string} defaults\n * @returns {object}\n */\nfunction getDefaults(defaults) {\n\n var VALUES = defaults.split(',');\n\n var VALUES_ARR = VALUES.map(function (value) {\n\n if (value === '') {\n return {};\n }\n\n var KEY_VAL = value.split('=');\n\n if (KEY_VAL.length !== 2) {\n throw new Error('Invalid setting ' + value);\n }\n\n var KEY = KEY_VAL[0];\n var VAL = KEY_VAL[1];\n\n var ALLOWED_DURATION = ['1', '2', '4', '8', '16', '32'];\n var ALLOWED_OCTAVE = ['4', '5', '6', '7'];\n var ALLOWED_BPM = ['25', '28', '31', '35', '40', '45', '50', '56', '63', '70', '80', '90', '100', '112', '125', '140', '160', '180', '200', '225', '250', '285', '320', '355', '400', '450', '500', '565', '635', '715', '800', '900'];\n\n switch (KEY) {\n case 'd':\n if (ALLOWED_DURATION.indexOf(VAL) !== -1) {\n return { duration: VAL };\n } else {\n throw new Error('Invalid duration ' + VAL);\n }\n case 'o':\n if (ALLOWED_OCTAVE.indexOf(VAL) === -1) {\n console.warn('Invalid octave ' + VAL);\n }\n return { octave: VAL };\n case 'b':\n if (ALLOWED_BPM.indexOf(VAL) === -1) {\n console.warn('Invalid BPM ' + VAL);\n }\n return { bpm: VAL };\n }\n });\n\n var VALUES_OBJ = _toObject({}, VALUES_ARR);\n\n var DEFAULT_VALUES = {\n duration: '4',\n octave: '6',\n bpm: '63'\n };\n\n return Object.assign(DEFAULT_VALUES, VALUES_OBJ);\n}\n\n/**\n * Convert an array of objects into an object\n *\n * @param {object} obj\n * @param {Array} arr\n * @returns {object}\n * @private\n */\nfunction _toObject(obj, arr) {\n\n if (arr.length === 0) {\n return obj;\n }\n\n var newObj = Object.assign(obj, arr[0]);\n\n return _toObject(newObj, arr.slice(1));\n}\n\n/**\n * Get the parsed melody data\n *\n * @param {string} melody\n * @param {object} defaults\n * @returns {Array}\n */\nfunction getData(melody, defaults) {\n\n var NOTES = melody.split(',');\n var BEAT_EVERY = 60000 / parseInt(defaults.bpm);\n\n return NOTES.map(function (note) {\n\n var NOTE_REGEX = /(1|2|4|8|16|32|64)?((?:[a-g]|h|p)#?){1}(\\.?)(4|5|6|7)?/;\n var NOTE_PARTS = note.match(NOTE_REGEX);\n\n var NOTE_DURATION = NOTE_PARTS[1] || parseInt(defaults.duration);\n var NOTE = NOTE_PARTS[2] === 'h' ? 'b' : NOTE_PARTS[2];\n var NOTE_DOTTED = NOTE_PARTS[3] === '.';\n var NOTE_OCTAVE = NOTE_PARTS[4] || parseInt(defaults.octave);\n\n return {\n note: NOTE,\n duration: _calculateDuration(BEAT_EVERY, parseFloat(NOTE_DURATION), NOTE_DOTTED),\n frequency: _calculateFrequency(NOTE, NOTE_OCTAVE)\n };\n });\n}\n\n/**\n * Calculate the frequency of a note\n *\n * @param {string} note\n * @param {number} octave\n * @returns {number}\n * @private\n */\nfunction _calculateFrequency(note, octave) {\n\n if (note === 'p') {\n return 0;\n }\n\n var C4 = 261.63;\n var TWELFTH_ROOT = Math.pow(2, 1 / 12);\n var N = _calculateSemitonesFromC4(note, octave);\n var FREQUENCY = C4 * Math.pow(TWELFTH_ROOT, N);\n\n return Math.round(FREQUENCY * 1e1) / 1e1;\n}\n\nfunction _calculateSemitonesFromC4(note, octave) {\n\n var NOTE_ORDER = ['c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#', 'a', 'a#', 'b'];\n var MIDDLE_OCTAVE = 4;\n var SEMITONES_IN_OCTAVE = 12;\n\n var OCTAVE_JUMP = (octave - MIDDLE_OCTAVE) * SEMITONES_IN_OCTAVE;\n\n return NOTE_ORDER.indexOf(note) + OCTAVE_JUMP;\n}\n\n/**\n * Calculate the duration a note should be played\n *\n * @param {number} beatEvery\n * @param {number} noteDuration\n * @param {boolean} isDotted\n * @returns {number}\n * @private\n */\nfunction _calculateDuration(beatEvery, noteDuration, isDotted) {\n var DURATION = beatEvery * 4 / noteDuration;\n var PROLONGED = isDotted ? DURATION / 2 : 0;\n return DURATION + PROLONGED;\n}\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/rtttl-parse/dist/index.js\n// module id = 0\n// module chunks = 0","const rtttlParse = require('rtttl-parse');\n\nmodule.exports = {\n play,\n stop\n};\n\nlet shouldStop = false;\n\nfunction play(rtttl) {\n\n try {\n const parsedRtttl = rtttlParse.parse(rtttl);\n const audioCtx = new (AudioContext || webkitAudioContext)();\n _playMelody(parsedRtttl.melody, audioCtx);\n } catch(err) {\n alert(err);\n }\n\n}\n\nfunction stop() {\n shouldStop = true;\n}\n\nfunction _playMelody(melody, audioCtx) {\n\n if (shouldStop) {\n shouldStop = false;\n return;\n }\n\n const osc = audioCtx.createOscillator();\n osc.type = 'triangle';\n osc.start(0);\n\n if (melody.length === 0) {\n return;\n }\n\n const note = melody[0];\n\n osc.frequency.value = note.frequency;\n osc.connect(audioCtx.destination);\n\n setTimeout(() => {\n osc.disconnect(audioCtx.destination);\n _playMelody(melody.slice(1), audioCtx, osc);\n }, note.duration);\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/index.js"],"sourceRoot":""}
--------------------------------------------------------------------------------
/dist/index.umd.min.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///index.umd.min.js","webpack:///webpack/bootstrap fa4d3bc25cd0532fef32","webpack:///./~/rtttl-parse/dist/index.js","webpack:///./src/index.js"],"names":["root","factory","exports","module","define","amd","this","modules","__webpack_require__","moduleId","installedModules","i","l","call","m","c","value","d","name","getter","o","Object","defineProperty","configurable","enumerable","get","n","__esModule","object","property","prototype","hasOwnProperty","p","s","parse","rtttl","SECTIONS","split","length","Error","NAME","getName","DEFAULTS","getDefaults","defaults","melody","getData","console","warn","VALUES","VALUES_ARR","map","KEY_VAL","KEY","VAL","ALLOWED_DURATION","ALLOWED_OCTAVE","ALLOWED_BPM","indexOf","duration","octave","bpm","VALUES_OBJ","_toObject","DEFAULT_VALUES","assign","obj","arr","slice","NOTES","BEAT_EVERY","parseInt","note","NOTE_PARTS","match","NOTE_DURATION","NOTE","NOTE_DOTTED","NOTE_OCTAVE","_calculateDuration","parseFloat","frequency","_calculateFrequency","TWELFTH_ROOT","Math","pow","N","_calculateSemitonesFromC4","FREQUENCY","round","NOTE_ORDER","OCTAVE_JUMP","beatEvery","noteDuration","isDotted","DURATION","play","parsedRtttl","rtttlParse","audioCtx","AudioContext","webkitAudioContext","_playMelody","err","alert","stop","shouldStop","osc","createOscillator","type","start","connect","destination","setTimeout","disconnect"],"mappings":"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","file":"index.umd.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"rtttlPlay\"] = factory();\n\telse\n\t\troot[\"rtttlPlay\"] = factory();\n})(this, function() {\nreturn \n\n\n// WEBPACK FOOTER //\n// webpack/universalModuleDefinition","(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"rtttlPlay\"] = factory();\n\telse\n\t\troot[\"rtttlPlay\"] = factory();\n})(this, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// identity function for calling harmony imports with the correct context\n/******/ \t__webpack_require__.i = function(value) { return value; };\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 1);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nmodule.exports = {\n parse: parse,\n getName: getName,\n getDefaults: getDefaults,\n getData: getData\n};\n\n/**\n * Parse RTTTL\n *\n * @param {string} rtttl - RTTTL String\n * @returns {object} - An object specifying frequency and duration for each note\n */\nfunction parse(rtttl) {\n\n var REQUIRED_SECTIONS_NUM = 3;\n var SECTIONS = rtttl.split(':');\n\n if (SECTIONS.length !== REQUIRED_SECTIONS_NUM) {\n throw new Error('Invalid RTTTL file.');\n }\n\n var NAME = getName(SECTIONS[0]);\n var DEFAULTS = getDefaults(SECTIONS[1]);\n var MELODY = getData(SECTIONS[2], DEFAULTS);\n\n return {\n name: NAME,\n defaults: DEFAULTS,\n melody: MELODY\n };\n}\n\n/**\n * Get ring tone name\n *\n * @param {string} name\n * @returns {string}\n */\nfunction getName(name) {\n\n var MAX_LENGTH = 10;\n\n if (name.length > MAX_LENGTH) {\n console.warn('Tune name should not exceed 10 characters.');\n }\n\n if (!name) {\n return 'Unknown';\n }\n\n return name;\n}\n\n/**\n * Get duration, octave and BPM\n *\n * @param {string} defaults\n * @returns {object}\n */\nfunction getDefaults(defaults) {\n\n var VALUES = defaults.split(',');\n\n var VALUES_ARR = VALUES.map(function (value) {\n\n if (value === '') {\n return {};\n }\n\n var KEY_VAL = value.split('=');\n\n if (KEY_VAL.length !== 2) {\n throw new Error('Invalid setting ' + value);\n }\n\n var KEY = KEY_VAL[0];\n var VAL = KEY_VAL[1];\n\n var ALLOWED_DURATION = ['1', '2', '4', '8', '16', '32'];\n var ALLOWED_OCTAVE = ['4', '5', '6', '7'];\n var ALLOWED_BPM = ['25', '28', '31', '35', '40', '45', '50', '56', '63', '70', '80', '90', '100', '112', '125', '140', '160', '180', '200', '225', '250', '285', '320', '355', '400', '450', '500', '565', '635', '715', '800', '900'];\n\n switch (KEY) {\n case 'd':\n if (ALLOWED_DURATION.indexOf(VAL) !== -1) {\n return { duration: VAL };\n } else {\n throw new Error('Invalid duration ' + VAL);\n }\n case 'o':\n if (ALLOWED_OCTAVE.indexOf(VAL) === -1) {\n console.warn('Invalid octave ' + VAL);\n }\n return { octave: VAL };\n case 'b':\n if (ALLOWED_BPM.indexOf(VAL) === -1) {\n console.warn('Invalid BPM ' + VAL);\n }\n return { bpm: VAL };\n }\n });\n\n var VALUES_OBJ = _toObject({}, VALUES_ARR);\n\n var DEFAULT_VALUES = {\n duration: '4',\n octave: '6',\n bpm: '63'\n };\n\n return Object.assign(DEFAULT_VALUES, VALUES_OBJ);\n}\n\n/**\n * Convert an array of objects into an object\n *\n * @param {object} obj\n * @param {Array} arr\n * @returns {object}\n * @private\n */\nfunction _toObject(obj, arr) {\n\n if (arr.length === 0) {\n return obj;\n }\n\n var newObj = Object.assign(obj, arr[0]);\n\n return _toObject(newObj, arr.slice(1));\n}\n\n/**\n * Get the parsed melody data\n *\n * @param {string} melody\n * @param {object} defaults\n * @returns {Array}\n */\nfunction getData(melody, defaults) {\n\n var NOTES = melody.split(',');\n var BEAT_EVERY = 60000 / parseInt(defaults.bpm);\n\n return NOTES.map(function (note) {\n\n var NOTE_REGEX = /(1|2|4|8|16|32|64)?((?:[a-g]|h|p)#?){1}(\\.?)(4|5|6|7)?/;\n var NOTE_PARTS = note.match(NOTE_REGEX);\n\n var NOTE_DURATION = NOTE_PARTS[1] || parseInt(defaults.duration);\n var NOTE = NOTE_PARTS[2] === 'h' ? 'b' : NOTE_PARTS[2];\n var NOTE_DOTTED = NOTE_PARTS[3] === '.';\n var NOTE_OCTAVE = NOTE_PARTS[4] || parseInt(defaults.octave);\n\n return {\n note: NOTE,\n duration: _calculateDuration(BEAT_EVERY, parseFloat(NOTE_DURATION), NOTE_DOTTED),\n frequency: _calculateFrequency(NOTE, NOTE_OCTAVE)\n };\n });\n}\n\n/**\n * Calculate the frequency of a note\n *\n * @param {string} note\n * @param {number} octave\n * @returns {number}\n * @private\n */\nfunction _calculateFrequency(note, octave) {\n\n if (note === 'p') {\n return 0;\n }\n\n var C4 = 261.63;\n var TWELFTH_ROOT = Math.pow(2, 1 / 12);\n var N = _calculateSemitonesFromC4(note, octave);\n var FREQUENCY = C4 * Math.pow(TWELFTH_ROOT, N);\n\n return Math.round(FREQUENCY * 1e1) / 1e1;\n}\n\nfunction _calculateSemitonesFromC4(note, octave) {\n\n var NOTE_ORDER = ['c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#', 'a', 'a#', 'b'];\n var MIDDLE_OCTAVE = 4;\n var SEMITONES_IN_OCTAVE = 12;\n\n var OCTAVE_JUMP = (octave - MIDDLE_OCTAVE) * SEMITONES_IN_OCTAVE;\n\n return NOTE_ORDER.indexOf(note) + OCTAVE_JUMP;\n}\n\n/**\n * Calculate the duration a note should be played\n *\n * @param {number} beatEvery\n * @param {number} noteDuration\n * @param {boolean} isDotted\n * @returns {number}\n * @private\n */\nfunction _calculateDuration(beatEvery, noteDuration, isDotted) {\n var DURATION = beatEvery * 4 / noteDuration;\n var PROLONGED = isDotted ? DURATION / 2 : 0;\n return DURATION + PROLONGED;\n}\n\n/***/ }),\n/* 1 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar rtttlParse = __webpack_require__(0);\n\nmodule.exports = {\n play: play,\n stop: stop\n};\n\nvar shouldStop = false;\n\nfunction play(rtttl) {\n\n try {\n var parsedRtttl = rtttlParse.parse(rtttl);\n var audioCtx = new (AudioContext || webkitAudioContext)();\n _playMelody(parsedRtttl.melody, audioCtx);\n } catch (err) {\n alert(err);\n }\n}\n\nfunction stop() {\n shouldStop = true;\n}\n\nfunction _playMelody(melody, audioCtx) {\n\n if (shouldStop) {\n shouldStop = false;\n return;\n }\n\n var osc = audioCtx.createOscillator();\n osc.type = 'triangle';\n osc.start(0);\n\n if (melody.length === 0) {\n return;\n }\n\n var note = melody[0];\n\n osc.frequency.value = note.frequency;\n osc.connect(audioCtx.destination);\n\n setTimeout(function () {\n osc.disconnect(audioCtx.destination);\n _playMelody(melody.slice(1), audioCtx, osc);\n }, note.duration);\n}\n\n/***/ })\n/******/ ]);\n});\n\n\n// WEBPACK FOOTER //\n// index.umd.min.js"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 1);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap fa4d3bc25cd0532fef32","\"use strict\";\n\nmodule.exports = {\n parse: parse,\n getName: getName,\n getDefaults: getDefaults,\n getData: getData\n};\n\n/**\n * Parse RTTTL\n *\n * @param {string} rtttl - RTTTL String\n * @returns {object} - An object specifying frequency and duration for each note\n */\nfunction parse(rtttl) {\n\n var REQUIRED_SECTIONS_NUM = 3;\n var SECTIONS = rtttl.split(':');\n\n if (SECTIONS.length !== REQUIRED_SECTIONS_NUM) {\n throw new Error('Invalid RTTTL file.');\n }\n\n var NAME = getName(SECTIONS[0]);\n var DEFAULTS = getDefaults(SECTIONS[1]);\n var MELODY = getData(SECTIONS[2], DEFAULTS);\n\n return {\n name: NAME,\n defaults: DEFAULTS,\n melody: MELODY\n };\n}\n\n/**\n * Get ring tone name\n *\n * @param {string} name\n * @returns {string}\n */\nfunction getName(name) {\n\n var MAX_LENGTH = 10;\n\n if (name.length > MAX_LENGTH) {\n console.warn('Tune name should not exceed 10 characters.');\n }\n\n if (!name) {\n return 'Unknown';\n }\n\n return name;\n}\n\n/**\n * Get duration, octave and BPM\n *\n * @param {string} defaults\n * @returns {object}\n */\nfunction getDefaults(defaults) {\n\n var VALUES = defaults.split(',');\n\n var VALUES_ARR = VALUES.map(function (value) {\n\n if (value === '') {\n return {};\n }\n\n var KEY_VAL = value.split('=');\n\n if (KEY_VAL.length !== 2) {\n throw new Error('Invalid setting ' + value);\n }\n\n var KEY = KEY_VAL[0];\n var VAL = KEY_VAL[1];\n\n var ALLOWED_DURATION = ['1', '2', '4', '8', '16', '32'];\n var ALLOWED_OCTAVE = ['4', '5', '6', '7'];\n var ALLOWED_BPM = ['25', '28', '31', '35', '40', '45', '50', '56', '63', '70', '80', '90', '100', '112', '125', '140', '160', '180', '200', '225', '250', '285', '320', '355', '400', '450', '500', '565', '635', '715', '800', '900'];\n\n switch (KEY) {\n case 'd':\n if (ALLOWED_DURATION.indexOf(VAL) !== -1) {\n return { duration: VAL };\n } else {\n throw new Error('Invalid duration ' + VAL);\n }\n case 'o':\n if (ALLOWED_OCTAVE.indexOf(VAL) === -1) {\n console.warn('Invalid octave ' + VAL);\n }\n return { octave: VAL };\n case 'b':\n if (ALLOWED_BPM.indexOf(VAL) === -1) {\n console.warn('Invalid BPM ' + VAL);\n }\n return { bpm: VAL };\n }\n });\n\n var VALUES_OBJ = _toObject({}, VALUES_ARR);\n\n var DEFAULT_VALUES = {\n duration: '4',\n octave: '6',\n bpm: '63'\n };\n\n return Object.assign(DEFAULT_VALUES, VALUES_OBJ);\n}\n\n/**\n * Convert an array of objects into an object\n *\n * @param {object} obj\n * @param {Array} arr\n * @returns {object}\n * @private\n */\nfunction _toObject(obj, arr) {\n\n if (arr.length === 0) {\n return obj;\n }\n\n var newObj = Object.assign(obj, arr[0]);\n\n return _toObject(newObj, arr.slice(1));\n}\n\n/**\n * Get the parsed melody data\n *\n * @param {string} melody\n * @param {object} defaults\n * @returns {Array}\n */\nfunction getData(melody, defaults) {\n\n var NOTES = melody.split(',');\n var BEAT_EVERY = 60000 / parseInt(defaults.bpm);\n\n return NOTES.map(function (note) {\n\n var NOTE_REGEX = /(1|2|4|8|16|32|64)?((?:[a-g]|h|p)#?){1}(\\.?)(4|5|6|7)?/;\n var NOTE_PARTS = note.match(NOTE_REGEX);\n\n var NOTE_DURATION = NOTE_PARTS[1] || parseInt(defaults.duration);\n var NOTE = NOTE_PARTS[2] === 'h' ? 'b' : NOTE_PARTS[2];\n var NOTE_DOTTED = NOTE_PARTS[3] === '.';\n var NOTE_OCTAVE = NOTE_PARTS[4] || parseInt(defaults.octave);\n\n return {\n note: NOTE,\n duration: _calculateDuration(BEAT_EVERY, parseFloat(NOTE_DURATION), NOTE_DOTTED),\n frequency: _calculateFrequency(NOTE, NOTE_OCTAVE)\n };\n });\n}\n\n/**\n * Calculate the frequency of a note\n *\n * @param {string} note\n * @param {number} octave\n * @returns {number}\n * @private\n */\nfunction _calculateFrequency(note, octave) {\n\n if (note === 'p') {\n return 0;\n }\n\n var C4 = 261.63;\n var TWELFTH_ROOT = Math.pow(2, 1 / 12);\n var N = _calculateSemitonesFromC4(note, octave);\n var FREQUENCY = C4 * Math.pow(TWELFTH_ROOT, N);\n\n return Math.round(FREQUENCY * 1e1) / 1e1;\n}\n\nfunction _calculateSemitonesFromC4(note, octave) {\n\n var NOTE_ORDER = ['c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#', 'a', 'a#', 'b'];\n var MIDDLE_OCTAVE = 4;\n var SEMITONES_IN_OCTAVE = 12;\n\n var OCTAVE_JUMP = (octave - MIDDLE_OCTAVE) * SEMITONES_IN_OCTAVE;\n\n return NOTE_ORDER.indexOf(note) + OCTAVE_JUMP;\n}\n\n/**\n * Calculate the duration a note should be played\n *\n * @param {number} beatEvery\n * @param {number} noteDuration\n * @param {boolean} isDotted\n * @returns {number}\n * @private\n */\nfunction _calculateDuration(beatEvery, noteDuration, isDotted) {\n var DURATION = beatEvery * 4 / noteDuration;\n var PROLONGED = isDotted ? DURATION / 2 : 0;\n return DURATION + PROLONGED;\n}\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/rtttl-parse/dist/index.js\n// module id = 0\n// module chunks = 0","const rtttlParse = require('rtttl-parse');\n\nmodule.exports = {\n play,\n stop\n};\n\nlet shouldStop = false;\n\nfunction play(rtttl) {\n\n try {\n const parsedRtttl = rtttlParse.parse(rtttl);\n const audioCtx = new (AudioContext || webkitAudioContext)();\n _playMelody(parsedRtttl.melody, audioCtx);\n } catch(err) {\n alert(err);\n }\n\n}\n\nfunction stop() {\n shouldStop = true;\n}\n\nfunction _playMelody(melody, audioCtx) {\n\n if (shouldStop) {\n shouldStop = false;\n return;\n }\n\n const osc = audioCtx.createOscillator();\n osc.type = 'triangle';\n osc.start(0);\n\n if (melody.length === 0) {\n return;\n }\n\n const note = melody[0];\n\n osc.frequency.value = note.frequency;\n osc.connect(audioCtx.destination);\n\n setTimeout(() => {\n osc.disconnect(audioCtx.destination);\n _playMelody(melody.slice(1), audioCtx, osc);\n }, note.duration);\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/index.js"],"sourceRoot":""}
--------------------------------------------------------------------------------