@benjamindehli/logic-pro-scripter-utils
v1.0.0
Published
TypeScript utilities and type definitions for Logic Pro Scripter API
Maintainers
Readme
Logic Pro Scripter Utils
A comprehensive TypeScript library providing type definitions, utilities, and helper functions for Apple Logic Pro's Scripter plugin. This package enables you to write type-safe JavaScript for MIDI processing in Logic Pro with full IntelliSense support and modern development practices.
Features
- Complete Type Definitions: Full TypeScript interfaces for all Logic Pro Scripter APIs
- MIDI Event Classes: Strongly-typed classes for all MIDI event types (NoteOn, NoteOff, ControlChange, etc.)
- Music Theory Utilities: Helper functions for scales, chords, note conversion, and transposition
- Parameter Management: Easy-to-use parameter definition utilities with common presets
- Timing Utilities: Tools for working with Logic Pro's timing information
- Debug Tools: Enhanced logging and debugging utilities for Scripter development
- Event Sequencing: Tools for creating complex MIDI sequences and arpeggios
- Performance Monitoring: Built-in performance measurement tools
Installation
npm install logic-pro-scripter-utilsQuick Start
Basic Usage
import { NoteOn, NoteOff, ControlChange, MIDIUtils, ParameterFactory, TraceLogger } from "logic-pro-scripter-utils";
// Simple transpose example
function HandleMIDI(event: Event) {
event.send(); // Send original
if (event instanceof NoteOn) {
// Transpose up an octave
const transposed = new NoteOn();
transposed.pitch = MIDIUtils.transposeNote(event.pitch, 12);
transposed.velocity = event.velocity;
transposed.channel = event.channel;
transposed.sendAfterMilliseconds(100);
}
}Parameter Definition
import { ParameterFactory } from "logic-pro-scripter-utils";
const PluginParameters = [
ParameterFactory.linear("Transpose", -24, 24, 0),
ParameterFactory.percentage("Mix", 50),
ParameterFactory.menu("Scale", ["Major", "Minor", "Dorian"], 0),
ParameterFactory.checkbox("Bypass", false)
];Music Theory Helpers
import { MIDIUtils, Scales, Chords } from "logic-pro-scripter-utils";
// Convert MIDI note to frequency
const freq = MIDIUtils.midiNoteToFrequency(60); // 261.63 Hz (Middle C)
// Get note name
const noteName = MIDIUtils.midiNoteToName(60); // "C4"
// Check if note is in scale
const isInCMajor = MIDIUtils.isInScale(64, 60, Scales.MAJOR); // true (E in C Major)
// Generate chord
const cMajorChord = Chords.MAJOR.map((interval) => 60 + interval); // [60, 64, 67]Enhanced Debugging
import { TraceLogger, MIDIEventLogger, DebugUtils } from "logic-pro-scripter-utils";
// Set up logging
TraceLogger.setLevel(TraceLevel.DEBUG);
MIDIEventLogger.setLogAllEvents(true);
function HandleMIDI(event: Event) {
// Log event details
MIDIEventLogger.logEvent(event, "Processing");
// Your processing logic here
TraceLogger.info("Processing note", { pitch: event.pitch });
event.send();
}API Reference
Event Classes
Base Event Class
abstract class Event {
channel: number; // MIDI channel (1-16)
articulationID: number; // Articulation ID (0-254)
readonly beatPos: number; // Event's beat position
send(): void;
sendAfterMilliseconds(ms: number): void;
sendAtBeat(beat: number): void;
sendAfterBeats(beat: number): void;
trace(): void;
toString(): string;
}MIDI Event Types
NoteOn- MIDI Note On eventsNoteOff- MIDI Note Off eventsControlChange- MIDI Control Change eventsProgramChange- MIDI Program Change eventsPitchBend- MIDI Pitch Bend eventsChannelPressure- MIDI Channel Pressure eventsPolyPressure- MIDI Polyphonic Pressure eventsTargetEvent- User-defined target events
Core Functions
// Required for MIDI event processing
type HandleMIDIFunction = (event: Event) => void;
// Optional timing-based processing
type ProcessMIDIFunction = () => void;
// Plugin lifecycle
type ResetFunction = () => void;
type ParameterChangedFunction = (param: number, value: number) => void;
// Global functions (available in Scripter environment)
declare function GetParameter(name: string): number;
declare function SetParameter(name: string, value: number): void;
declare function GetTimingInfo(): TimingInfo;
declare function Trace(message: any): void;Timing Information
interface TimingInfo {
readonly playing: boolean; // Transport is running
readonly blockStartBeat: number; // Block start beat position
readonly blockEndBeat: number; // Block end beat position
readonly blockLength: number; // Block length in beats
readonly tempo: number; // Current tempo
readonly meterNumerator: number; // Time signature numerator
readonly meterDenominator: number; // Time signature denominator
readonly cycling: boolean; // Transport is cycling
readonly leftCycleBeat: number; // Cycle start position
readonly rightCycleBeat: number; // Cycle end position
}Parameter Types
interface PluginParameter {
name: string;
type: "lin" | "log" | "indexed" | "checkbox" | "menu";
minValue?: number;
maxValue?: number;
defaultValue?: number;
numberOfSteps?: number;
valueStrings?: string[];
unit?: string;
}Utility Classes
MIDIUtils
midiNoteToFrequency(note)- Convert MIDI note to HzfrequencyToMidiNote(freq)- Convert Hz to MIDI notemidiNoteToName(note)- Convert MIDI note to name (e.g., "C4")noteNameToMidi(name)- Convert note name to MIDI notetransposeNote(note, semitones)- Transpose a noteisInScale(note, root, scale)- Check if note is in scalenormalizeVelocity(velocity)- Convert velocity to 0-1 rangeapplyVelocityCurve(velocity, curve)- Apply velocity curve
ParameterFactory
linear(name, min, max, default)- Linear parameterlogarithmic(name, min, max, default)- Logarithmic parametercheckbox(name, default)- Boolean parametermenu(name, options, default)- Menu parametergainDB(name, min, max, default)- Gain in dBfrequency(name, min, max, default)- Frequency in Hzpercentage(name, default)- Percentage parameter
EventSequencer
class EventSequencer {
addEvent(event: Event, time: number): void;
sendSequence(startTime?: number): void;
clear(): void;
getLength(): number;
}Arpeggiator
class Arpeggiator {
setNotes(notes: number[]): void;
setPattern(pattern: number[]): void;
getNextNote(): number | null;
reset(): void;
static readonly PATTERNS = {
UP: [0, 1, 2, 3],
DOWN: [3, 2, 1, 0],
UP_DOWN: [0, 1, 2, 3, 2, 1]
// ... more patterns
};
}Musical Constants
Scales
const Scales = {
MAJOR: [0, 2, 4, 5, 7, 9, 11],
MINOR: [0, 2, 3, 5, 7, 8, 10],
PENTATONIC_MAJOR: [0, 2, 4, 7, 9],
BLUES: [0, 3, 5, 6, 7, 10]
// ... more scales
};Chords
const Chords = {
MAJOR: [0, 4, 7],
MINOR: [0, 3, 7],
MAJOR_7: [0, 4, 7, 11],
MINOR_7: [0, 3, 7, 10]
// ... more chords
};MIDI Constants
const MIDIControllers = {
MODULATION: 1,
VOLUME: 7,
PAN: 10,
SUSTAIN_PEDAL: 64
// ... more controllers
};
const MIDINotes = {
MIDDLE_C: 60,
A440: 69,
C4: 60,
C5: 72
// ... more notes
};Examples
Chord Generator
import { NoteOn, Chords, MIDIUtils } from "logic-pro-scripter-utils";
function HandleMIDI(event: Event) {
if (event instanceof NoteOn) {
// Send original note
event.send();
// Generate major chord
const chordType = Chords.MAJOR;
chordType.forEach((interval, index) => {
if (index === 0) return; // Skip root (already sent)
const chordNote = new NoteOn();
chordNote.pitch = event.pitch + interval;
chordNote.velocity = Math.round(event.velocity * 0.8); // Softer
chordNote.channel = event.channel;
chordNote.send();
});
} else {
event.send();
}
}Scale Quantizer
import { NoteOn, MIDIUtils, Scales } from "logic-pro-scripter-utils";
const PluginParameters = [
ParameterFactory.menu("Root", ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"], 0),
ParameterFactory.menu("Scale", ["Major", "Minor", "Dorian", "Pentatonic"], 0)
];
function HandleMIDI(event: Event) {
if (event instanceof NoteOn) {
const rootNote = GetParameter("Root");
const scaleType = GetParameter("Scale");
const scales = [Scales.MAJOR, Scales.MINOR, Scales.DORIAN, Scales.PENTATONIC_MAJOR];
// Quantize to scale
let quantizedPitch = event.pitch;
const scale = scales[scaleType];
if (!MIDIUtils.isInScale(event.pitch, rootNote, scale)) {
// Find nearest scale note
let minDistance = 12;
for (let offset = -6; offset <= 6; offset++) {
const testPitch = event.pitch + offset;
if (MIDIUtils.isInScale(testPitch, rootNote, scale)) {
if (Math.abs(offset) < Math.abs(minDistance)) {
minDistance = offset;
}
}
}
quantizedPitch = event.pitch + minDistance;
}
event.pitch = quantizedPitch;
}
event.send();
}Advanced Arpeggiator
import { NoteOn, NoteOff, Arpeggiator, TimingUtils, ParameterFactory } from "logic-pro-scripter-utils";
let arp = new Arpeggiator();
let heldNotes = new Set<number>();
let nextNoteTime = 0;
const PluginParameters = [
ParameterFactory.menu("Pattern", ["Up", "Down", "UpDown"], 0),
ParameterFactory.linear("Rate", 0.125, 2, 0.25, 16) // Note divisions
];
var NeedsTimingInfo = true;
function HandleMIDI(event: Event) {
if (event instanceof NoteOn) {
heldNotes.add(event.pitch);
updateArpeggiator();
} else if (event instanceof NoteOff) {
heldNotes.delete(event.pitch);
updateArpeggiator();
} else {
event.send(); // Pass through other events
}
}
function ProcessMIDI() {
const timing = GetTimingInfo();
if (timing.playing && heldNotes.size > 0) {
const rate = GetParameter("Rate");
if (timing.blockStartBeat >= nextNoteTime) {
const nextNote = arp.getNextNote();
if (nextNote !== null) {
const noteOn = new NoteOn();
noteOn.pitch = nextNote;
noteOn.velocity = 80;
noteOn.sendAtBeat(nextNoteTime);
// Schedule note off
const noteOff = new NoteOff();
noteOff.pitch = nextNote;
noteOff.sendAtBeat(nextNoteTime + rate * 0.8);
}
nextNoteTime += rate;
}
}
}
function updateArpeggiator() {
const notes = Array.from(heldNotes).sort((a, b) => a - b);
arp.setNotes(notes);
const patternIndex = GetParameter("Pattern");
const patterns = [Arpeggiator.PATTERNS.UP, Arpeggiator.PATTERNS.DOWN, Arpeggiator.PATTERNS.UP_DOWN];
arp.setPattern(patterns[patternIndex]);
}Development
Building
npm run buildTesting
npm testLinting
npm run lintContributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
License
GPL-3.0 License - see the LICENSE file for details.
Related
Changelog
1.0.0
- Initial release
- Complete TypeScript definitions for Logic Pro Scripter API
- MIDI utilities and music theory helpers
- Parameter management utilities
- Debug and tracing tools
- Event sequencing and arpeggiator classes
- Comprehensive examples and documentation
