Skip to main content
Glama
MusicTheory.tsโ€ข5.01 kB
export class MusicTheory { private scales = { major: [0, 2, 4, 5, 7, 9, 11], minor: [0, 2, 3, 5, 7, 8, 10], dorian: [0, 2, 3, 5, 7, 9, 10], phrygian: [0, 1, 3, 5, 7, 8, 10], lydian: [0, 2, 4, 6, 7, 9, 11], mixolydian: [0, 2, 4, 5, 7, 9, 10], aeolian: [0, 2, 3, 5, 7, 8, 10], locrian: [0, 1, 3, 5, 6, 8, 10], pentatonic: [0, 2, 4, 7, 9], blues: [0, 3, 5, 6, 7, 10], chromatic: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], wholetone: [0, 2, 4, 6, 8, 10], harmonic_minor: [0, 2, 3, 5, 7, 8, 11], melodic_minor: [0, 2, 3, 5, 7, 9, 11] }; private chordProgressions = { pop: ['I', 'V', 'vi', 'IV'], jazz: ['IIM7', 'V7', 'IM7'], blues: ['I7', 'I7', 'I7', 'I7', 'IV7', 'IV7', 'I7', 'I7', 'V7', 'IV7', 'I7', 'V7'], folk: ['I', 'IV', 'I', 'V'], rock: ['I', 'bVII', 'IV', 'I'], classical: ['I', 'IV', 'V', 'I'], modal: ['i', 'bVII', 'IV', 'i'], edm: ['i', 'VI', 'III', 'VII'] }; generateScale(root: string, scaleName: keyof typeof this.scales): string[] { const noteNames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']; const rootIndex = noteNames.indexOf(root.toUpperCase()); if (rootIndex === -1) { throw new Error(`Invalid root note: ${root}`); } const scale = this.scales[scaleName]; if (!scale) { throw new Error(`Invalid scale: ${scaleName}`); } return scale.map(interval => { const noteIndex = (rootIndex + interval) % 12; return noteNames[noteIndex]; }); } generateChordProgression(key: string, style: keyof typeof this.chordProgressions): string { const progression = this.chordProgressions[style]; if (!progression) { throw new Error(`Invalid progression style: ${style}`); } const chordMap: Record<string, string> = { 'I': `"${key}"`, 'I7': `"${key}7"`, 'i': `"${key.toLowerCase()}m"`, 'ii': `"${this.getNote(key, 2)}m"`, 'IIM7': `"${this.getNote(key, 2)}m7"`, 'iii': `"${this.getNote(key, 4)}m"`, 'III': `"${this.getNote(key, 4)}"`, 'IV': `"${this.getNote(key, 5)}"`, 'IV7': `"${this.getNote(key, 5)}7"`, 'V': `"${this.getNote(key, 7)}"`, 'V7': `"${this.getNote(key, 7)}7"`, 'vi': `"${this.getNote(key, 9)}m"`, 'VI': `"${this.getNote(key, 9)}"`, 'VII': `"${this.getNote(key, 11)}"`, 'bVII': `"${this.getNote(key, 10)}"`, 'IM7': `"${key}maj7"` }; return progression .map(chord => chordMap[chord] || `"${key}"`) .join(' '); } getNote(root: string, semitones: number): string { const noteNames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']; const rootIndex = noteNames.indexOf(root.toUpperCase()); if (rootIndex === -1) return root; return noteNames[(rootIndex + semitones) % 12]; } generateEuclideanRhythm(hits: number, steps: number): string { if (hits > steps) { throw new Error('Hits cannot exceed steps'); } const pattern: boolean[] = new Array(steps).fill(false); const interval = steps / hits; for (let i = 0; i < hits; i++) { const index = Math.floor(i * interval); pattern[index] = true; } return pattern.map(hit => hit ? '1' : '~').join(' '); } generatePolyrhythm(pattern1: number, pattern2: number, length: number = 16): string { const rhythm1 = this.generateEuclideanRhythm(pattern1, length); const rhythm2 = this.generateEuclideanRhythm(pattern2, length); return `[${rhythm1}], [${rhythm2}]`; } getScaleNotes(root: string, scaleName: keyof typeof this.scales, octave: number = 3): string[] { const scale = this.generateScale(root, scaleName); return scale.map(note => `${note.toLowerCase()}${octave}`); } generateArpeggio(chord: string, pattern: string = 'up'): string { const patterns: Record<string, number[]> = { 'up': [0, 1, 2, 3], 'down': [3, 2, 1, 0], 'updown': [0, 1, 2, 3, 2, 1], 'random': [0, 2, 1, 3, 0, 3, 1, 2] }; const arpPattern = patterns[pattern] || patterns['up']; const notes = this.getChordNotes(chord); return arpPattern .map(index => notes[index % notes.length]) .join(' '); } private getChordNotes(chord: string): string[] { // Simplified chord parsing - would need more sophisticated implementation const root = chord.replace(/[^A-G#]/g, ''); const type = chord.replace(/[A-G#]/g, ''); const intervals: Record<string, number[]> = { '': [0, 4, 7], // major 'm': [0, 3, 7], // minor '7': [0, 4, 7, 10], // dominant 7 'maj7': [0, 4, 7, 11], // major 7 'm7': [0, 3, 7, 10], // minor 7 'dim': [0, 3, 6], // diminished 'aug': [0, 4, 8] // augmented }; const chordIntervals = intervals[type] || intervals['']; return chordIntervals.map(interval => { const note = this.getNote(root, interval); return `${note.toLowerCase()}3`; }); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/williamzujkowski/strudel-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server