### Install Development Dependencies Source: https://github.com/cuthbertlab/music21j/blob/master/README.md Run these commands on first-time setup to install necessary development dependencies and browser binaries for testing. ```sh $ npm install $ npx playwright install chromium ``` -------------------------------- ### Start Local Python Server and Run Demos Source: https://github.com/cuthbertlab/music21j/blob/master/doc/index.html Navigate to the music21j directory, build the project with webpack, and start a Python server to view demos. Access the demos at http://localhost:8000/testHTML/. ```bash % cd ~/git/music21j % grunt webpack % python start_python_server.py ``` -------------------------------- ### Start Development Server Source: https://github.com/cuthbertlab/music21j/blob/master/README.md Use this command to start Vite's development server for local development with fast rebuilds and live reload. Navigate to http://localhost:5173/testHTML to view tests. ```sh $ npm run dev ``` -------------------------------- ### Install music21j via npm Source: https://context7.com/cuthbertlab/music21j/llms.txt Install the music21j library using npm. This command is for terminal usage. ```bash npm install music21j ``` -------------------------------- ### Install and Include music21j Source: https://github.com/cuthbertlab/music21j/blob/master/testHTML/renderTinyNotationDivs.html To use TinyNotation rendering, install the music21j library via npm and include the debug script in your HTML. The second script tag is only needed if the divs already exist on the page. ```html ``` -------------------------------- ### Keyboard Jazz Highlight Callback Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21.keyboard.html An example of a callback function for jazz highlighting on a keyboard, intended for use with MIDI events. Requires prior setup of MIDI callbacks. ```javascript var midiCallbacksPlay = [ music21.miditools.makeChords, music21.miditools.sendToMIDIjs, music21.keyboard.jazzHighlight.bind(k) ]; ``` -------------------------------- ### Create AudioBuffer from Buffers Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_audioRecording.js.html Creates an AudioBuffer from provided audio data buffers. This is a setup step for playing back audio. ```javascript playBuffers(buffers) { const channels = 2; const numFrames = buffers[0].length; const audioBuffer = this.context.createBuffer( channels, numFrames, this.context.sampleRate ); ``` -------------------------------- ### Basic TinyNotation Example Source: https://github.com/cuthbertlab/music21j/blob/master/testHTML/renderTinyNotationDivs.html Define a div with classes 'music21 tinyNotation' to display musical notation. Clicking the div will play the notation. ```html
c4 d8 e8 f2
(click me) ``` -------------------------------- ### AbstractScale: Get Realization of Scale Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_scale.js.html Calculates the pitches of a scale starting from a given pitch object. It caches the one-octave realization for efficiency. Handles string or Pitch object inputs for the starting pitch. ```javascript getRealization(pitchObj, unused_stepOfPitch, unused_minPitch, unused_maxPitch, unused_direction, unused_reverse) { // if (direction === undefined) { // direction = DIRECTION_ASCENDING; // } // if (stepOfPitch === undefined) { // stepOfPitch = 1; // } if (typeof pitchObj === 'string') { pitchObj = new pitch.Pitch(pitchObj); } else { pitchObj = pitchObj.clone(); } const post = [pitchObj]; for (const intV of this._net) { pitchObj = intV.transposePitch(pitchObj); post.push(pitchObj); } return post; } ``` -------------------------------- ### Keyboard Initialization and Configuration Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21.keyboard.html Demonstrates the minimum usage and configuration options for the Keyboard class. ```APIDOC ## Minimum Usage ```javascript const kd = document.getElementById('keyboardDiv'); const k = new music21.keyboard.Keyboard(); k.appendKeyboard(kd, 6, 57); // 88 key keyboard ``` ## Configurable Properties ```javascript // configurable: k.scaleFactor = 1.2; // default 1 k.whiteKeyWidth = 40; // default 23 ``` ``` -------------------------------- ### Start User Media Stream Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_audioSearch.js.html Sets up the audio context, creates a MediaStreamSource, and connects an analyser node. This function patches Safari and requires some time to initialize. ```javascript export function userMediaStarted(audioStream) { /** * This function which patches Safari requires some time to get started * so we call it on object creation. */ config.sampleBuffer = new Float32Array(config.fftSize / 2); const mediaStreamSource = config.audioContext.createMediaStreamSource( audioStream ); const analyser = config.audioContext.createAnalyser(); analyser.fftSize = config.fftSize; mediaStreamSource.connect(analyser); config.currentAnalyser = analyser; animateLoop(); } ``` -------------------------------- ### Get Element Sounding When Another Element Starts Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_stream.js.html Retrieves the first element in the stream that is sounding when a given element begins. If multiple elements are sounding, it prioritizes elements of the same class as the input element, otherwise returning the first encountered. ```javascript playingWhenAttacked(el, elStream) { let elOffset; if (elStream !== undefined) { elOffset = el.getOffsetBySite(elStream); } else { elOffset = el.offset; } const otherElements = this.getElementsByOffset(elOffset, elOffset, { mustBeginInSpan: false }); if (otherElements.length === 0) { return undefined; } else if (otherElements.length === 1) { return otherElements.get(0); } else { for (const thisEl of otherElements) { if (el.constructor === thisEl.constructor) { return thisEl; } } return otherElements.get(0); } } ``` -------------------------------- ### Main Function for Setup Source: https://github.com/cuthbertlab/music21j/blob/master/testHTML/colorChanger.html Initializes a music21 stream with notes, sets key and time signatures, and appends the stream's DOM representation to the page. Also demonstrates appending a Roman numeral chord. ```javascript function main() { s = undefined; const k = new music21.key.Key('D'); s = new music21.stream.Measure(); s.keySignature = k; s.timeSignature = new music21.meter.TimeSignature('4/4'); const n = new music21.note.Note('G4'); n.duration.type = 'half'; s.append(n); const n2 = new music21.note.Note('A4'); s.append(n2); const n3 = new music21.note.Note('B4'); s.append(n3); s.autoBeam = false; const d = getColorDOM(s); document.querySelector('#SVGDiv') .appendChild(d); const sChord = new music21.stream.Measure(); sChord.timeSignature = new music21.meter.TimeSignature('4/4'); const ch = new music21.roman.RomanNumeral('IV', k); ch.duration.type = 'whole'; sChord.keySignature = k; sChord.append(ch); sChord.appendNewDOM(document.querySelector('#SVGDiv')); } ``` -------------------------------- ### Note Start Setter for Interval Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_interval.js.html Sets the starting note of the interval and automatically calculates and sets the ending note by transposing the starting note's pitch. ```javascript set noteStart(n) { this._noteStart = n; const p1 = n.pitch; const p2 = this.transposePitch(p1); this._noteEnd = n.clone(); this._noteEnd.pitch = p2; } ``` -------------------------------- ### Initialize and Connect Audio Source Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_audioRecording.js.html Sets up the audio context, creates a Web Worker for asynchronous audio processing, and connects the source to the processing node and audio destination. This is essential for enabling recording functionality. ```javascript const zeroGain = this.audioContext.createGain(); zeroGain.gain.value = 0.0; inputPoint.connect(zeroGain); zeroGain.connect(this.audioContext.destination); } / * Creates a worker to receive and process all the messages asynchronously. * * @param {GainNode} source; */ connectSource(source) { / * * @type {BaseAudioContext} */ const context = source.context; this.context = context; this.setNode(); // create a Worker with inline code... const workerBlob = new Blob(['(', recorderWorkerJs, ')()'], { type: 'application/javascript', }); const workerURL = URL.createObjectURL(workerBlob); this.worker = new Worker(workerURL); /** * When worker sends a message, we just send it to the currentCallback... */ this.worker.onmessage = e => { const blob = e.data; this.currCallback(blob); }; URL.revokeObjectURL(workerURL); this.worker.postMessage({ command: 'init', config: { sampleRate: this.context.sampleRate, }, }); /** * Whenever the ScriptProcessorNode receives enough audio to process * (i.e., this.bufferLen stereo samples; default 4096), then it calls onaudioprocess * which is set up to send the event's .getChannelData to the WebWorker via a * postMessage. * * The 'record' command sends no message back. */ this.node.onaudioprocess = e => { if (!this.recording) { return; } this.worker.postMessage({ command: 'record', buffer: [ e.inputBuffer.getChannelData(0), e.inputBuffer.getChannelData(1), ], }); }; source.connect(this.node); /** * polyfill for Chrome error. * * if the ScriptProcessorNode (this.node) is not connected to an output * the "onaudioprocess" event is not triggered in Chrome. */ this.node.connect(this.context.destination); } ``` -------------------------------- ### Install Music21j in a JavaScript/TypeScript Project Source: https://github.com/cuthbertlab/music21j/blob/master/README.md Install music21j as a dependency for your JavaScript or TypeScript project using npm. ```bash $ npm install --save music21j ``` -------------------------------- ### Setup Download Link Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_audioRecording.js.html Creates a downloadable link for a given Blob object. It generates a URL for the blob and sets the href and download attributes of a specified HTML element. ```javascript setupDownload(blob, filename, elementId) { elementId = elementId || 'save'; const url = (window.URL || window.webkitURL).createObjectURL(blob); const link = document.getElementById(elementId); link.href = url; link.download = filename || 'output.wav'; } ``` -------------------------------- ### Get Stem Direction from Clef Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_note.js.html Placeholder method to get stem direction from a clef. Returns undefined. ```javascript getStemDirectionFromClef(clef) { return undefined; } ``` -------------------------------- ### Get Length of Beams List in music21j Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_beam.js.html Accessor property to get the number of beams currently in the beamsList. ```javascript get length() { return this.beamsList.length; } ``` -------------------------------- ### Code Highlighting Setup Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_tempo.js.html Configures code blocks within tutorial and readme sections for syntax highlighting using Sunlight. It adds specific classes for highlighting and line numbers, and then calls Sunlight.highlightAll() to process all highlighted code. ```javascript $( ".tutorial-section pre, .readme-section pre" ).each( function () { var $this = $( this ); var example = $this.find( "code" ); exampleText = example.html(); var lang = /{@lang (.*?)}/.exec( exampleText ); if ( lang && lang[1] ) { exampleText = exampleText.replace( lang[0], "" ); example.html( exampleText ); lang = lang[1]; } else { lang = "javascript"; } if ( lang ) { $this .addClass( "sunlight-highlight-" + lang ) .addClass( "linenums" ) .html( example.html() ); } } ); Sunlight.highlightAll( { lineNumbers : true, showMenu : true, enableDoclinks : true } ); ``` -------------------------------- ### Start Note Sequence Interval Source: https://github.com/cuthbertlab/music21j/blob/master/testHTML/demo-Cuthbert.html This function starts an interval timer to repeatedly call playSeventy, initiating the sequence of notes. ```javascript function refreshMe() { stopIntervalId = setInterval(playSeventy, 100); } ``` -------------------------------- ### Create and Configure Keyboard Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21.keyboard.html Demonstrates the minimum usage for creating a keyboard instance and appending it to a DOM element. Configuration options for scaleFactor and whiteKeyWidth are also shown. ```javascript const kd = document.getElementById('keyboardDiv'); const k = new music21.keyboard.Keyboard(); k.appendKeyboard(kd, 6, 57); // 88 key keyboard // configurable: k.scaleFactor = 1.2; // default 1 k.whiteKeyWidth = 40; // default 23 ``` -------------------------------- ### Build music21j Project Source: https://github.com/cuthbertlab/music21j/blob/master/doc/index.html Use this command to build the music21j project. ```bash $ grunt webpack ``` -------------------------------- ### Get VexFlow Duration String Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_duration.js.html Illustrates how to get the VexFlow-compatible duration string from a Duration object. Dots are appended to the base type string. ```javascript var d = new music21.duration.Duration(2); d.vexflowDuration == 'h'; // true; d.dots = 2; d.vexflowDuration == 'hdd'; // true; ``` -------------------------------- ### Build Documentation Source: https://github.com/cuthbertlab/music21j/blob/master/doc/index.html Command to build the project's documentation using JSDoc. ```bash grunt jsdoc ``` -------------------------------- ### Create MusicXML Tie Elements Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_musicxml_m21ToXml.js.html Generates MusicXML 'tie' elements based on the type of tie (start or stop). Handles 'continue' ties by creating both a 'stop' and a 'start' tie. ```javascript if (t.type === 'continue') { musicxmlTieType = 'stop'; } const mxTie = this.doc.createElement('tie'); mxTie.setAttribute('type', musicxmlTieType); mxTieList.push(mxTie); if (t.type === 'continue') { const mxTie = this.doc.createElement('tie'); mxTie.setAttribute('type', 'start'); mxTieList.push(mxTie); } return mxTieList; } ``` -------------------------------- ### Run Music21j Configuration Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_parseLoader.js.html Initializes music21j by loading configuration from window or a JSON attribute, setting up paths, and rendering HTML elements. It handles soundfont loading and HTML rendering based on configuration. ```javascript export function runConfiguration() { let conf; // noinspection JSUnresolvedVariable if (typeof window.m21conf !== 'undefined') { // noinspection JSUnresolvedVariable conf = window.m21conf; } else { conf = loadConfiguration(); } conf.warnBanner = (conf.warnBanner !== undefined) ? conf.warnBanner : warnBanner(); conf.loadSoundfont = (conf.loadSoundfont !== undefined) ? conf.loadSoundfont : getM21attribute('loadSoundFont') || true; conf.renderHTML = (conf.renderHTML !== undefined) ? conf.renderHTML : getM21attribute('renderHTML'); if (conf.renderHTML === undefined) { conf.renderHTML = true; } conf.m21basePath = getBasePath(); fixUrls(conf); loadDefaultSoundfont(conf); renderHTML(); } ``` -------------------------------- ### Multiple Midi Players on a Page Source: https://github.com/cuthbertlab/music21j/blob/master/testHTML/embedPlayer.html This example demonstrates how to instantiate and manage multiple MIDI players on the same HTML page. Each player can be configured independently to play different MIDI files. ```javascript // noinspection SpellCheckingInspection song = [ // Sinding - Rustles of Spring Op-32 No-3 'data:audio/midi;base64,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 ``` -------------------------------- ### Basic webmidi usage with MIDI input selector Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21.module_webmidi.html This example demonstrates the smallest usage of the webmidi toolkit. It requires jQuery and the music21/miditools module. The code sets up a MIDI input selector and defines a callback function to process incoming MIDI events, displaying them as music21 notes. ```html MIDI In/Jazz Test for Music21j
MIDI Input:
``` -------------------------------- ### Python to Javascript Conversion Example Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_fromPython.js.html This example demonstrates the typical workflow for converting a Python-encoded music21 stream to a music21j object. First, freeze the stream in Python, then load it in Javascript using the Converter. ```python s = corpus.parse('bwv66.6') stringRepresentingM21JsonPickle = s.freezeStream('jsonpickle') ``` ```javascript pyConv = new music21.fromPython.Converter(); s = pyConv.run(stringRepresentingM21JsonPickle); ``` -------------------------------- ### Build Project Source: https://github.com/cuthbertlab/music21j/blob/master/README.md Run this command to produce the UMD bundle (build/music21.debug.js) and sourcemaps, suitable for browser use or npm publishing. ```sh $ npm run build ``` -------------------------------- ### Generate Numeric Range in JavaScript Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_common.js.html Creates an array of numbers within a specified range. Supports start, stop, and step values. If only one argument is provided, it is treated as the stop value with a start of 0 and a step of 1. ```javascript export function range(start, stop, step) { if (step === undefined) { step = 1; } if (stop === undefined) { stop = start; start = 0; } const count = Math.ceil((stop - start) / step); return Array.apply(0, Array(count)).map((e, i) => i * step + start); } ``` -------------------------------- ### Initialize MIDI Input and Metronome Source: https://github.com/cuthbertlab/music21j/blob/master/testHTML/midiInChords.html Sets up the music21 stream, metronome, and MIDI input callbacks. Requires a MIDI keyboard and Jazz Plugin. ```javascript let s; let metro; function appendElement(appendObject) { if (s.length > 7) { s.elements = s.elements.slice(1) } s.append(appendObject); const svgDiv = document.querySelector("#svgDiv"); svgDiv.replaceChildren(); s.appendNewDOM(svgDiv); } function main() { s = new music21.stream.Measure(); s.clef = new music21.clef.TrebleClef(); s.renderOptions.staffLines = 5; metro = new music21.tempo.Metronome(); metro.addDiv(document.querySelector("#metronomeDiv")); music21.miditools.config.metronome = metro; music21.webmidi.createSelector(document.querySelector("#putMidiSelectHere")); music21.miditools.callbacks.general = [ music21.miditools.makeChords, music21.miditools.sendToMIDIjs, ]; music21.miditools.callbacks.sendOutChord = appendElement; } document.addEventListener('DOMContentLoaded', () => { main(); }); ``` -------------------------------- ### MIDI Input Setup with Custom Failure Handler Source: https://github.com/cuthbertlab/music21j/blob/master/testHTML/midiInChordsCustomFail.html Configures MIDI input to create chords and handle access failures with a custom alert message. Requires a MIDI keyboard and the Jazz Plugin. ```javascript let s; let metro; function appendElement(appendObject) { if (s.length > 7) { s.elements = s.elements.slice(1) } s.append(appendObject); const svgDiv = document.querySelector("#svgDiv"); svgDiv.replaceChildren(); s.appendNewDOM(svgDiv); } function main() { s = new music21.stream.Measure(); s.clef = new music21.clef.TrebleClef(); s.renderOptions.staffLines = 5; metro = new music21.tempo.Metronome(); metro.addDiv(document.querySelector("#metronomeDiv")); music21.miditools.config.metronome = metro; music21.webmidi.createSelector( document.querySelector("#putMidiSelectHere"), {onAccessFailure: e => { alert(e.message + '(' + e.name + ')') }} ); music21.miditools.callbacks.general = [ music21.miditools.makeChords, music21.miditools.sendToMIDIjs, ]; music21.miditools.callbacks.sendOutChord = appendElement; } document.addEventListener('DOMContentLoaded', () => { main(); }); ``` -------------------------------- ### Set Measure Start Attributes Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_musicxml_m21ToXml.js.html Creates and appends MusicXML 'attributes' for the start of a measure, including divisions, key signature, time signature, and clef if they differ from the parent or are defined. Appends to the XML root only if new attributes are added. ```javascript setMxAttributesObjectForStartOfMeasure() { const m = this.stream; const mxAttributes = this.doc.createElement('attributes'); let appendToRoot = false; this.currentDivisions = divisionsPerQuarter; if (this.parent === undefined || this.currentDivisions !== this.parent.lastDivisions) { const mxDivisions = this.subElement(mxAttributes, 'divisions'); mxDivisions.innerHTML = this.currentDivisions.toString(); this.parent.lastDivisions = this.currentDivisions; appendToRoot = true; } if (m.classes.includes('Measure')) { if (m._keySignature !== undefined) { mxAttributes.appendChild(this.keySignatureToXml(m._keySignature)); appendToRoot = true; } if (m._timeSignature !== undefined) { mxAttributes.appendChild(this.timeSignatureToXml(m._timeSignature)); appendToRoot = true; } // todo SenzaMisura... if (m._clef !== undefined) { mxAttributes.appendChild(this.clefToXml(m._clef)); appendToRoot = true; } } // staffLayout // transpositionInterval // measureStyle if (appendToRoot) { this.xmlRoot.appendChild(mxAttributes); } return mxAttributes; } ``` -------------------------------- ### duration Getter/Setter Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_stream.js.html Gets or sets the duration of the stream. ```APIDOC ## duration Getter/Setter ### Description Manages the overall duration of the stream. ### Getter `get duration()` - **Returns**: A `duration.Duration` object representing the stream's duration. If not explicitly set, it's derived from the `highestTime`. ### Setter `set duration(newDuration)` - **Parameters**: - **newDuration** (duration.Duration) - The new duration to set for the stream. ``` -------------------------------- ### Initialize and Load MIDI File Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_miditools.js.html Initializes the MIDI player, sets playback speed, loads a soundfont, and then loads a base64 encoded MIDI file. Includes callbacks for successful loading and failure. ```javascript const player = this.player; player.timeWarp = this.speed; const m21MidiPlayer = this; loadSoundfont('acoustic_grand_piano', () => { player.loadFile( b64data, () => { // success m21MidiPlayer.fileLoaded(); }, undefined, // loading e => { // failure console.log(e); } ); }); ``` -------------------------------- ### StreamIterator: Get Voices Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_stream_iterator.js.html Adds a filter to select only 'Voice' elements. ```javascript get voices() { return this.addFilter(new filters.ClassFilter('Voice')); } ``` -------------------------------- ### Initialize MIDI Input and Keyboard Handling Source: https://github.com/cuthbertlab/music21j/blob/master/testHTML/midiInKeyChords.html Sets up the music21 stream, metronome, and keyboard. Configures MIDI input callbacks to process incoming notes as chords and highlight them on a virtual keyboard. Ensure WebMIDI is enabled in Chrome or use the Jazz plugin. ```javascript let s; let metro; function appendElement(appendObject) { if (s.length > 7) { s.elements = s.elements.slice(1) } s.append(appendObject); const svgDiv = document.querySelector("#svgDiv"); svgDiv.replaceChildren(); s.appendNewDOM(svgDiv); } function main() { s = new music21.stream.Measure(); s.clef = new music21.clef.TrebleClef(); s.renderOptions.staffLines = 5; metro = new music21.tempo.Metronome(); metro.addDiv(document.querySelector("#metronomeDiv")); music21.miditools.config.metronome = metro; const k = new music21.keyboard.Keyboard(); const kd = document.getElementById('keyboardDiv'); k.startPitch = 18; // 6 k.endPitch = 39; // 57 k.appendKeyboard(kd); // 37key keyboard music21.webmidi.createSelector(document.querySelector("#putMidiSelectHere")); music21.miditools.callbacks.general = [ music21.miditools.makeChords, music21.keyboard.jazzHighlight.bind(k), music21.miditools.sendToMIDIjs, ]; music21.miditools.callbacks.sendOutChord = appendElement; } document.addEventListener('DOMContentLoaded', () => { main(); }); ``` -------------------------------- ### StreamIterator: Get Spanners Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_stream_iterator.js.html Adds a filter to select only 'Spanner' elements. ```javascript get spanners() { return this.addFilter(new filters.ClassFilter('Spanner')); } ``` -------------------------------- ### Initialize Audio Recording Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_audioRecording.js.html Initializes the audio recording system by polyfilling navigator and requesting microphone access. This method should be called to start the audio input process. ```javascript initAudio() { this.polyfillNavigator(); // not sure what function signature this wants. // noinspection JSCheckFunctionSignatures navigator.getUserMedia( { audio: { mandatory: { googEchoCancellation: 'false', googAutoGainControl: 'false', googNoiseSuppression: 'false', googHighpassFilter: 'false', // 'echoCancellation': false, // 'autoGainControl': false, // 'noiseSuppression': false, // 'highpassFilter': false, }, optional: [], }, }, s => this.audioStreamConnected(s), error => { console.log('Error getting audio -- try on google Chrome?'); console.log(error); } ); } ``` -------------------------------- ### StreamIterator: Get Parts Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_stream_iterator.js.html Adds a filter to select only 'Part' elements. ```javascript get parts() { return this.addFilter(new filters.ClassFilter('Part')); } ``` -------------------------------- ### exports.MusicOrdinals Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21.interval.html An array containing ordinal names for musical terms, starting from Unison. ```APIDOC ## exports.MusicOrdinals ### Description An array containing ordinal names for musical terms, such as Unison, Second, Third, etc. ### Example ```javascript for (var i = 1; i < music21.interval.MusicOrdinals.length; i++) { console.log(i, music21.interval.MusicOrdinals[i]); } // Output: // 1, Unison // 2, Second // 3, Third // ... // 8, Octave // ... // 15, Double Octave ``` ``` -------------------------------- ### prepareFlat Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_vfShow.js.html Main internal routine to prepare a flat stream. ```APIDOC ## prepareFlat ### Description Main internal routine to prepare a flat stream. ### Method prepareFlat(s, stack, optionalStave, optional_renderOp) ### Parameters #### Path Parameters - **s** (music21.stream.Stream) - A flat stream object. - **stack** (music21.vfShow.RenderStack) - A RenderStack object to prepare into. - **optionalStave** (Vex.Flow.Stave) - An optional existing stave. - **optional_renderOp** (Object) - Render options. Passed to {@link music21.vfShow.Renderer#renderStave} ### Returns - **stave** (Vex.Flow.Stave) - The staff to return. (also changes the `stack` parameter and runs `makeNotation` on s) ``` -------------------------------- ### Main Initialization Function Source: https://github.com/cuthbertlab/music21j/blob/master/testHTML/showKeyboard.html Sets up the main music21j objects including Parts, Measures, a Score, and a Metronome. It configures rendering options, inserts clefs, and initializes the keyboard and MIDI callbacks. Also sets up the event listener for switching between single and grand staff views. ```javascript function main() { p = new music21.stream.Part(); m = new music21.stream.Measure(); p.insert(0, m); m.clef = new music21.clef.TrebleClef(); p.renderOptions.scaleFactor = { x: 1.5, y: 1.5 }; p1 = new music21.stream.Part(); m1 = new music21.stream.Measure(); p1.insert(0, m1); m1.clef = new music21.clef.TrebleClef(); p2 = new music21.stream.Part(); m2 = new music21.stream.Measure(); p2.insert(0, m2); m2.clef = new music21.clef.BassClef(); sc = new music21.stream.Score(); sc.insert(0, p1); sc.insert(0, p2); sc.partSpacing = 90; sc.renderOptions.scaleFactor = { x: 1.5, y: 1.5 }; metro = new music21.tempo.Metronome(); metro.addDiv(document.querySelector("#metronomeDiv")); music21.miditools.config.metronome = metro; music21.miditools.config.maxDelay = 200; music21.webmidi.createSelector(document.querySelector("#putMidiSelectHere")); const staffRadio = document.querySelector('input[type=radio][name=staffNumberSelector]') staffRadio.addEventListener('change', e => { if (e.target.value === 'singleStaff') { document.querySelector("#svgDiv").style.display = 'block'; document.querySelector("#svgDivGrandStaff").style.display = 'none'; music21.miditools.callbacks.sendOutChord = appendElement; } else if (e.target.value === 'grandStaff') { document.querySelector("#svgDiv").style.display = 'none'; document.querySelector("#svgDivGrandStaff").style.displ } }); } ``` -------------------------------- ### Enharmonic Equivalents Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_pitch.js.html Methods for getting higher and lower enharmonic equivalents of a pitch. ```APIDOC ## Enharmonic Equivalents ### Description Provides methods to get the higher or lower enharmonic equivalent of a pitch. ### Methods - `getHigherEnharmonic(inPlace=false)`: Returns the higher enharmonic equivalent. If `inPlace` is true, modifies the current pitch. - `getLowerEnharmonic(inPlace=false)`: Returns the lower enharmonic equivalent. If `inPlace` is true, modifies the current pitch. ### Parameters - `inPlace` (boolean): Optional. If true, modifies the current pitch object. Defaults to false. ``` -------------------------------- ### StreamIterator: Get Notes Source: https://github.com/cuthbertlab/music21j/blob/master/doc/music21_stream_iterator.js.html Adds a filter to select only note elements, excluding rests. ```javascript get notes() { return this.addFilter(new filters.ClassFilter('NotRest')); } ```