From cf8ae2ab9199ed36d3df95e4bba707fe00506193 Mon Sep 17 00:00:00 2001 From: Matthew Hasbach Date: Sat, 22 Aug 2015 23:43:58 -0400 Subject: [PATCH] Add documentation. Closes #1. --- README.md | 175 +++++++++++++++++++++++++++++++++++++++++- dist/pixiPianoRoll.js | 126 ++++++++++++++++++++++++++++-- gulpfile.js | 19 ++++- lib/pixiPianoRoll.js | 122 ++++++++++++++++++++++++++++- package.json | 2 + 5 files changed, 431 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 42ab0c6..0e96379 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,174 @@ -# pixi-piano-roll +## Modules +
+
pixiPianoRoll
+

JavaScript 2D WebGL / Canvas animated piano roll

+
+
+## Typedefs +
+
transportTime : string
+

Playback position expressed in bars:quarters:sixteenths format (e.g. "1:2:0")

+
+
note : string | number
+

Musical note expressed in Scientific notation, Helmholtz notation, piano key number, audio frequency (the closest note will be used), or MIDI note number

+
+
noteDuration : string | number
+

Note duration expressed as a number (e.g. 1 for a whole note) or string (e.g. "4n" for a quarter note)

+
+
pianoRollAPI : Object
+

The piano roll API

+
+
+ +## pixiPianoRoll +JavaScript 2D WebGL / Canvas animated piano roll -JavaScript 2D WebGL / Canvas animated piano roll \ No newline at end of file +**Author:** Matthew Hasbach +**License**: MIT +**Copyright**: Matthew Hasbach 2015 + +### pixiPianoRoll(opt) ? [pianoRollAPI](#pianoRollAPI) ? +Instantiate a pixiPianoRoll + +**Kind**: Exported function + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| opt | Object | | Options object | +| [opt.width] | number | 900 | Width of the piano roll | +| [opt.height] | number | 400 | Height of the piano roll | +| [opt.noteColor] | number | Object.<number> | musicalScaleColors.dDJameson | Hexadecimal color of every note or object that has music note property names and hexadecimal color values. See [musical-scale-colors](https://github.com/mjhasbach/musical-scale-colors) for palettes (including the default). | +| [opt.noteColor] | number | 0x333333 | Hexadecimal color of the grid lines | +| [opt.noteColor] | number | 0 | Hexadecimal color of the background | +| [opt.bpm] | number | 140 | Beats per minute | +| [opt.antialias] | boolean | true | Whether or not the renderer will use antialiasing | +| [opt.zoom] | number | 4 | Amount of visible measures | +| [opt.resolution] | number | 2 | Amount of vertical grid lines per measure | +| [opt.time] | [transportTime](#transportTime) | 0:0:0 | The [transportTime](#transportTime) at which playback will begin | +| [opt.renderer] | string | "WebGLRenderer" | Determines the renderer type. Must be `"WebGLRenderer"` or `"CanvasRenderer"`. | +| [opt.noteFormat] | string | "String" | The format of the [notes](#note) in `opt.noteData`. `"String"` for scientific or Helmholtz notation, `"Key"` for piano key numbers, `"Frequency"` for audio frequencies, or `"MIDI"` for MIDI note numbers. | +| [opt.noteData] | Array.<Array.<transportTime, note, noteDuration>> | [] | See the typedefs for [transportTime](#transportTime), [note](#note), and [noteDuration](#noteDuration) | + +**Example** +```js +var pianoRoll = pixiPianoRoll({ + width: 900, + height: 400, + noteColor: 0xdb000f, + gridLineColor: 0x333333, + backgroundColor: 0x1a0002, + bpm: 140, + antialias: true, + zoom: 4, + resolution: 2, + time: '0:0:0', + renderer: 'WebGLRenderer', + noteFormat: 'String', + noteData: [ + ['0:0:0', 'C4', '2n'], + ['0:0:0', 'D4', '2n'], + ['0:0:0', 'E4', '2n'], + ['0:2:0', 'B4', '4n'], + ['0:3:0', 'A#4', '4n'] + ] +}); + +document.getElementsByTagName('body')[0].appendChild(pianoRoll.view); + +pianoRoll.playback.play(); +``` + +## transportTime : string +Playback position expressed in bars:quarters:sixteenths format (e.g. `"1:2:0"`) + +**Kind**: global typedef + +## note : string | number +Musical note expressed in [Scientific notation](https://en.wikipedia.org/wiki/Scientific_pitch_notation), [Helmholtz notation](https://en.wikipedia.org/wiki/Helmholtz_pitch_notation), [piano key number](https://en.wikipedia.org/wiki/Piano_key_frequencies), [audio frequency](https://en.wikipedia.org/wiki/Audio_frequency) (the closest note will be used), or [MIDI](https://en.wikipedia.org/wiki/MIDI) note number + +**Kind**: global typedef + +## noteDuration : string | number +Note duration expressed as a number (e.g. `1` for a whole note) or string (e.g. `"4n"` for a quarter note) + +**Kind**: global typedef + +## pianoRollAPI : Object +The piano roll API + +**Kind**: global typedef + +* [pianoRollAPI](#pianoRollAPI) : Object + * [.playback](#pianoRollAPI.playback) : Object + * [.toggle([time])](#pianoRollAPI.playback.toggle) + * [.play([time])](#pianoRollAPI.playback.play) + * [.pause()](#pianoRollAPI.playback.pause) + * [.seek(time)](#pianoRollAPI.playback.seek) + * [.bpm](#pianoRollAPI.bpm) : number + * [.playing](#pianoRollAPI.playing) : boolean + * [.view](#pianoRollAPI.view) : HTMLElement + + +### pianoRollAPI.playback : Object +Contains methods that control playback + +**Kind**: static property of [pianoRollAPI](#pianoRollAPI) + +* [.playback](#pianoRollAPI.playback) : Object + * [.toggle([time])](#pianoRollAPI.playback.toggle) + * [.play([time])](#pianoRollAPI.playback.play) + * [.pause()](#pianoRollAPI.playback.pause) + * [.seek(time)](#pianoRollAPI.playback.seek) + + +#### playback.toggle([time]) +Pause if playing or play if paused + +**Kind**: static method of [playback](#pianoRollAPI.playback) + +| Param | Type | Description | +| --- | --- | --- | +| [time] | [transportTime](#transportTime) | If paused, the position to begin playing. If omitted, playback will begin at the current position. | + + +#### playback.play([time]) +Begin playback + +**Kind**: static method of [playback](#pianoRollAPI.playback) + +| Param | Type | Description | +| --- | --- | --- | +| [time] | [transportTime](#transportTime) | The position to begin playing. If omitted, playback will begin at the current position. | + + +#### playback.pause() +Pause playback + +**Kind**: static method of [playback](#pianoRollAPI.playback) + +#### playback.seek(time) +Change the playback position + +**Kind**: static method of [playback](#pianoRollAPI.playback) + +| Param | Type | Description | +| --- | --- | --- | +| time | [transportTime](#transportTime) | The new playback position | + + +### pianoRollAPI.bpm : number +Change the bpm by changing this property + +**Kind**: static property of [pianoRollAPI](#pianoRollAPI) + +### pianoRollAPI.playing : boolean +Whether or not playback is ongoing + +**Kind**: static property of [pianoRollAPI](#pianoRollAPI) +**Read only**: true + +### pianoRollAPI.view : HTMLElement +The piano roll canvas element + +**Kind**: static property of [pianoRollAPI](#pianoRollAPI) +**Read only**: true diff --git a/dist/pixiPianoRoll.js b/dist/pixiPianoRoll.js index 4e0d28f..709d8d7 100644 --- a/dist/pixiPianoRoll.js +++ b/dist/pixiPianoRoll.js @@ -7,6 +7,77 @@ root.pixiPianoRoll = factory(root.PIXI, root.teoria, root.musicalScaleColors); } }(this, function(pixi, teoria, musicalScaleColors) { +/** + * JavaScript 2D WebGL / Canvas animated piano roll + * @module pixiPianoRoll + * @author Matthew Hasbach + * @copyright Matthew Hasbach 2015 + * @license MIT + */ + +/** + * Playback position expressed in bars:quarters:sixteenths format (e.g. `"1:2:0"`) + * @typedef {string} transportTime + * @global + */ + +/** + * Musical note expressed in [Scientific notation]{@link https://en.wikipedia.org/wiki/Scientific_pitch_notation}, [Helmholtz notation]{@link https://en.wikipedia.org/wiki/Helmholtz_pitch_notation}, [piano key number]{@link https://en.wikipedia.org/wiki/Piano_key_frequencies}, [audio frequency]{@link https://en.wikipedia.org/wiki/Audio_frequency} (the closest note will be used), or [MIDI]{@link https://en.wikipedia.org/wiki/MIDI} note number + * @typedef {string|number} note + * @global + */ + +/** + * Note duration expressed as a number (e.g. `1` for a whole note) or string (e.g. `"4n"` for a quarter note) + * @typedef {string|number} noteDuration + * @global + */ + +/** + * Instantiate a pixiPianoRoll + * @alias module:pixiPianoRoll + * @param {Object} opt - Options object + * @param {number} [opt.width=900] - Width of the piano roll + * @param {number} [opt.height=400] - Height of the piano roll + * @param {number|Object} [opt.noteColor=musicalScaleColors.dDJameson] - Hexadecimal color of every note or object that has music note property names and hexadecimal color values. See [musical-scale-colors]{@link https://github.com/mjhasbach/musical-scale-colors} for palettes (including the default). + * @param {number} [opt.noteColor=0x333333] - Hexadecimal color of the grid lines + * @param {number} [opt.noteColor=0] - Hexadecimal color of the background + * @param {number} [opt.bpm=140] - Beats per minute + * @param {boolean} [opt.antialias=true] - Whether or not the renderer will use antialiasing + * @param {number} [opt.zoom=4] - Amount of visible measures + * @param {number} [opt.resolution=2] - Amount of vertical grid lines per measure + * @param {transportTime} [opt.time=0:0:0] - The [transportTime]{@link transportTime} at which playback will begin + * @param {string} [opt.renderer=WebGLRenderer] - Determines the renderer type. Must be `"WebGLRenderer"` or `"CanvasRenderer"`. + * @param {string} [opt.noteFormat=String] - The format of the [notes]{@link note} in `opt.noteData`. `"String"` for scientific or Helmholtz notation, `"Key"` for piano key numbers, `"Frequency"` for audio frequencies, or `"MIDI"` for MIDI note numbers. + * @param {Array.>} [opt.noteData=[]] - See the typedefs for [transportTime]{@link transportTime}, [note]{@link note}, and [noteDuration]{@link noteDuration} + * @returns {pianoRollAPI} + * @example +var pianoRoll = pixiPianoRoll({ + width: 900, + height: 400, + noteColor: 0xdb000f, + gridLineColor: 0x333333, + backgroundColor: 0x1a0002, + bpm: 140, + antialias: true, + zoom: 4, + resolution: 2, + time: '0:0:0', + renderer: 'WebGLRenderer', + noteFormat: 'String', + noteData: [ + ['0:0:0', 'C4', '2n'], + ['0:0:0', 'D4', '2n'], + ['0:0:0', 'E4', '2n'], + ['0:2:0', 'B4', '4n'], + ['0:3:0', 'A#4', '4n'] + ] +}); + +document.getElementsByTagName('body')[0].appendChild(pianoRoll.view); + +pianoRoll.playback.play(); + */ 'use strict'; var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })(); @@ -367,24 +438,50 @@ function pixiPianoRoll(opt) { renderer.render(stage); - var pianoRoll = Object.defineProperties({ + /** + * The piano roll API + * @typedef pianoRollAPI + * @type {Object} + * @global + */ + var pianoRollAPI = Object.defineProperties({ + /** + * Contains methods that control playback + * @memberof pianoRollAPI + * @type {Object} + */ playback: { + /** + * Pause if playing or play if paused + * @param {transportTime} [time] - If paused, the position to begin playing. If omitted, playback will begin at the current position. + */ toggle: function toggle(time) { - playing ? pianoRoll.playback.pause() : pianoRoll.playback.play(time); + playing ? pianoRollAPI.playback.pause() : pianoRollAPI.playback.play(time); }, + /** + * Begin playback + * @param {transportTime} [time] - The position to begin playing. If omitted, playback will begin at the current position. + */ play: function play(time) { if (!playing) { if (time) { - pianoRoll.playback.seek(time); + pianoRollAPI.playback.seek(time); } playing = true; requestAnimationFrame(animate); } }, + /** + * Pause playback + */ pause: function pause() { playing = false; }, + /** + * Change the playback position + * @param {transportTime} time - The new playback position + */ seek: function seek(time) { var xTime = -transportTimeToX(time), xDiff = noteContainer.x - xTime; @@ -396,7 +493,12 @@ function pixiPianoRoll(opt) { } } }, { - bpm: { + bpm: { /** + * Change the bpm by changing this property + * @memberof pianoRollAPI + * @type {number} + */ + set: function set(bpm) { setBPM(bpm); }, @@ -404,6 +506,13 @@ function pixiPianoRoll(opt) { enumerable: true }, playing: { + /** + * Whether or not playback is ongoing + * @memberof pianoRollAPI + * @type {boolean} + * @readonly + */ + get: function get() { return playing; }, @@ -411,6 +520,13 @@ function pixiPianoRoll(opt) { enumerable: true }, view: { + /** + * The piano roll canvas element + * @memberof pianoRollAPI + * @type {HTMLElement} + * @readonly + */ + get: function get() { return renderer.view; }, @@ -419,7 +535,7 @@ function pixiPianoRoll(opt) { } }); - return pianoRoll; + return pianoRollAPI; } return pixiPianoRoll; })); diff --git a/gulpfile.js b/gulpfile.js index 82bd7b5..b2e9b89 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,10 +1,12 @@ var gulp = require('gulp'), path = require('path'), umd = require('gulp-umd'), + gutil = require('gulp-util'), babel = require('gulp-babel'), rename = require('gulp-rename'), uglify = require('gulp-uglify'), - runSequence = require('run-sequence'); + runSequence = require('run-sequence'), + gulpJsdoc2md = require('gulp-jsdoc-to-markdown'); var libDir = 'lib', moduleName = 'pixiPianoRoll', @@ -40,10 +42,23 @@ gulp.task('minify', function() { .pipe(gulp.dest('dist')); }); +gulp.task('docs', function(){ + return gulp.src('lib/*.js') + .pipe(gulpJsdoc2md()) + .on('error', function(err){ + gutil.log(gutil.colors.red('documentation generation failed'), err.message); + }) + .pipe(rename(function(path){ + path.basename = 'README'; + path.extname = '.md'; + })) + .pipe(gulp.dest('.')); +}); + gulp.task('watch', function() { gulp.watch(path.join(libDir, '*.js'), ['ES6ToES5UMD']); }); gulp.task('default', function(cb) { - runSequence('ES6ToES5UMD', 'minify', cb); + runSequence('ES6ToES5UMD', 'minify', 'docs', cb); }); \ No newline at end of file diff --git a/lib/pixiPianoRoll.js b/lib/pixiPianoRoll.js index 01e2656..cead236 100644 --- a/lib/pixiPianoRoll.js +++ b/lib/pixiPianoRoll.js @@ -1,3 +1,74 @@ +/** + * JavaScript 2D WebGL / Canvas animated piano roll + * @module pixiPianoRoll + * @author Matthew Hasbach + * @copyright Matthew Hasbach 2015 + * @license MIT + */ + +/** + * Playback position expressed in bars:quarters:sixteenths format (e.g. `"1:2:0"`) + * @typedef {string} transportTime + * @global + */ + +/** + * Musical note expressed in [Scientific notation]{@link https://en.wikipedia.org/wiki/Scientific_pitch_notation}, [Helmholtz notation]{@link https://en.wikipedia.org/wiki/Helmholtz_pitch_notation}, [piano key number]{@link https://en.wikipedia.org/wiki/Piano_key_frequencies}, [audio frequency]{@link https://en.wikipedia.org/wiki/Audio_frequency} (the closest note will be used), or [MIDI]{@link https://en.wikipedia.org/wiki/MIDI} note number + * @typedef {string|number} note + * @global + */ + +/** + * Note duration expressed as a number (e.g. `1` for a whole note) or string (e.g. `"4n"` for a quarter note) + * @typedef {string|number} noteDuration + * @global + */ + +/** + * Instantiate a pixiPianoRoll + * @alias module:pixiPianoRoll + * @param {Object} opt - Options object + * @param {number} [opt.width=900] - Width of the piano roll + * @param {number} [opt.height=400] - Height of the piano roll + * @param {number|Object} [opt.noteColor=musicalScaleColors.dDJameson] - Hexadecimal color of every note or object that has music note property names and hexadecimal color values. See [musical-scale-colors]{@link https://github.com/mjhasbach/musical-scale-colors} for palettes (including the default). + * @param {number} [opt.noteColor=0x333333] - Hexadecimal color of the grid lines + * @param {number} [opt.noteColor=0] - Hexadecimal color of the background + * @param {number} [opt.bpm=140] - Beats per minute + * @param {boolean} [opt.antialias=true] - Whether or not the renderer will use antialiasing + * @param {number} [opt.zoom=4] - Amount of visible measures + * @param {number} [opt.resolution=2] - Amount of vertical grid lines per measure + * @param {transportTime} [opt.time=0:0:0] - The [transportTime]{@link transportTime} at which playback will begin + * @param {string} [opt.renderer=WebGLRenderer] - Determines the renderer type. Must be `"WebGLRenderer"` or `"CanvasRenderer"`. + * @param {string} [opt.noteFormat=String] - The format of the [notes]{@link note} in `opt.noteData`. `"String"` for scientific or Helmholtz notation, `"Key"` for piano key numbers, `"Frequency"` for audio frequencies, or `"MIDI"` for MIDI note numbers. + * @param {Array.>} [opt.noteData=[]] - See the typedefs for [transportTime]{@link transportTime}, [note]{@link note}, and [noteDuration]{@link noteDuration} + * @returns {pianoRollAPI} + * @example +var pianoRoll = pixiPianoRoll({ + width: 900, + height: 400, + noteColor: 0xdb000f, + gridLineColor: 0x333333, + backgroundColor: 0x1a0002, + bpm: 140, + antialias: true, + zoom: 4, + resolution: 2, + time: '0:0:0', + renderer: 'WebGLRenderer', + noteFormat: 'String', + noteData: [ + ['0:0:0', 'C4', '2n'], + ['0:0:0', 'D4', '2n'], + ['0:0:0', 'E4', '2n'], + ['0:2:0', 'B4', '4n'], + ['0:3:0', 'A#4', '4n'] + ] +}); + +document.getElementsByTagName('body')[0].appendChild(pianoRoll.view); + +pianoRoll.playback.play(); + */ function pixiPianoRoll(opt) { const colors = { black: 0, @@ -262,24 +333,50 @@ function pixiPianoRoll(opt) { renderer.render(stage); - let pianoRoll = { + /** + * The piano roll API + * @typedef pianoRollAPI + * @type {Object} + * @global + */ + let pianoRollAPI = { + /** + * Contains methods that control playback + * @memberof pianoRollAPI + * @type {Object} + */ playback: { + /** + * Pause if playing or play if paused + * @param {transportTime} [time] - If paused, the position to begin playing. If omitted, playback will begin at the current position. + */ toggle(time) { - playing ? pianoRoll.playback.pause() : pianoRoll.playback.play(time); + playing ? pianoRollAPI.playback.pause() : pianoRollAPI.playback.play(time); }, + /** + * Begin playback + * @param {transportTime} [time] - The position to begin playing. If omitted, playback will begin at the current position. + */ play(time) { if (!playing) { if (time) { - pianoRoll.playback.seek(time); + pianoRollAPI.playback.seek(time); } playing = true; requestAnimationFrame(animate); } }, + /** + * Pause playback + */ pause() { playing = false; }, + /** + * Change the playback position + * @param {transportTime} time - The new playback position + */ seek(time) { let xTime = -transportTimeToX(time), xDiff = noteContainer.x - xTime; @@ -290,16 +387,33 @@ function pixiPianoRoll(opt) { renderer.render(stage); } }, + /** + * Change the bpm by changing this property + * @memberof pianoRollAPI + * @type {number} + */ set bpm(bpm) { setBPM(bpm); }, + /** + * Whether or not playback is ongoing + * @memberof pianoRollAPI + * @type {boolean} + * @readonly + */ get playing() { return playing; }, + /** + * The piano roll canvas element + * @memberof pianoRollAPI + * @type {HTMLElement} + * @readonly + */ get view() { return renderer.view; } }; - return pianoRoll; + return pianoRollAPI; } \ No newline at end of file diff --git a/package.json b/package.json index 356fdf8..eba7f7e 100644 --- a/package.json +++ b/package.json @@ -24,9 +24,11 @@ "devDependencies": { "gulp": "~3.9.0", "gulp-babel": "~5.2.0", + "gulp-jsdoc-to-markdown": "~1.1.1", "gulp-rename": "~1.2.2", "gulp-uglify": "~1.2.0", "gulp-umd": "~0.2.0", + "gulp-util": "~3.0.6", "release-script": "~0.2.1", "run-sequence": "~1.1.2" },