From b8c44d7560630d269c6729b65d250841497dba12 Mon Sep 17 00:00:00 2001 From: Joris Griffioen Date: Sun, 21 Aug 2022 19:51:37 -0400 Subject: [PATCH] feat: cleaner types & smart message values --- src/index.browser.ts | 1 - src/index.ts | 1 - src/midiMessage/guards.ts | 23 ++++--- src/midiMessage/index.spec.ts | 16 +++-- src/midiMessage/index.ts | 62 ++++++++++++------- src/midiMessage/midiHexHelpers.ts | 5 +- src/midiMessage/types/index.ts | 3 - src/types/BankSettings.ts | 5 +- src/types/GlobalSettings.ts | 5 +- src/{midiMessage => }/types/Message.ts | 4 +- src/types/MessageStack.ts | 17 +++++ .../types/MidiMessageType.ts | 0 src/types/RawMessage.ts | 24 +++++++ src/{midiMessage => }/types/SmartMessage.ts | 18 +++++- .../{Messages.ts => SmartMessageType.ts} | 40 ------------ src/types/index.ts | 9 ++- tsconfig.json | 2 +- 17 files changed, 140 insertions(+), 95 deletions(-) delete mode 100644 src/midiMessage/types/index.ts rename src/{midiMessage => }/types/Message.ts (93%) create mode 100644 src/types/MessageStack.ts rename src/{midiMessage => }/types/MidiMessageType.ts (100%) create mode 100644 src/types/RawMessage.ts rename src/{midiMessage => }/types/SmartMessage.ts (88%) rename src/types/{Messages.ts => SmartMessageType.ts} (51%) diff --git a/src/index.browser.ts b/src/index.browser.ts index d7f41f6..7687c16 100644 --- a/src/index.browser.ts +++ b/src/index.browser.ts @@ -6,7 +6,6 @@ export * from './types'; export { PirateMidiDevice } from './PirateMidiDevice'; export { ValidationError } from './ValidationError'; export * from './midiMessage'; -export * from './midiMessage/types'; export { getMockDevice } from './mock'; /** diff --git a/src/index.ts b/src/index.ts index 843abc1..eaa14ed 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,7 +6,6 @@ export * from './types'; export { PirateMidiDevice } from './PirateMidiDevice'; export { ValidationError } from './ValidationError'; export * from './midiMessage'; -export * from './midiMessage/types'; export { getMockDevice } from './mock'; /** diff --git a/src/midiMessage/guards.ts b/src/midiMessage/guards.ts index d959968..70c5926 100644 --- a/src/midiMessage/guards.ts +++ b/src/midiMessage/guards.ts @@ -1,14 +1,17 @@ -import { BaseMessage, ExpMessage, SmartMessage } from '../types/Messages'; -import { convertStatusByteToType } from './midiHexHelpers'; -import { MidiMessageType } from './types'; +import { + RawMessage, + RawExpMessage, + RawSmartMessage, + MidiMessageType, +} from '../types'; + +export const isMidiMessageType = (type: string): type is MidiMessageType => + Object.values(MidiMessageType).includes(type as MidiMessageType); export const isExpressionMidiMessage = ( - message: BaseMessage | ExpMessage | SmartMessage -): message is ExpMessage => !!(message as ExpMessage).sweep; + message: RawMessage | RawExpMessage | RawSmartMessage +): message is RawExpMessage => !!(message as RawExpMessage).sweep; export const isSmartMidiMessage = ( - message: BaseMessage | ExpMessage | SmartMessage -): message is SmartMessage => { - const type = convertStatusByteToType(message.statusByte); - return type === MidiMessageType.SmartMessage; -}; + message: RawMessage | RawExpMessage | RawSmartMessage +): message is RawSmartMessage => message.statusByte === '70'; diff --git a/src/midiMessage/index.spec.ts b/src/midiMessage/index.spec.ts index fe7a9a8..ee17111 100644 --- a/src/midiMessage/index.spec.ts +++ b/src/midiMessage/index.spec.ts @@ -1,12 +1,16 @@ import { decodeMidiMessage, encodeMidiMessage } from '.'; -import { SmartMessageType } from '../types/Messages'; -import { MidiMessageType } from './types'; -import { SmartSwitchMessage } from './types/SmartMessage'; +import { + MidiMessageType, + RawMessage, + SmartMessageType, + SmartSwitchMessage, +} from '../types'; const encodedMessages = { programChange: { statusByte: 'c0', dataByte1: '00', + dataByte2: '00', outputs: { midi0: true, flexi1: true, @@ -132,7 +136,7 @@ const decodedMessages = { smartSwitchToggle: { type: 'SmartMessage', smartType: 'switchToggle', - side: 'primary', + side: 'Primary', switchIndex: 4, }, }; @@ -166,7 +170,9 @@ describe('MidiMessage', () => { }); describe('smart messages', () => { it('should throw for invalid data', () => { - expect(() => decodeMidiMessage({ statusByte: '70' })).toThrow(); + expect(() => + decodeMidiMessage({ statusByte: '70' } as RawMessage) + ).toThrow(); }); it('should decode a switch toggle message', () => { expect(decodeMidiMessage(encodedMessages.smartSwitchToggle)).toEqual( diff --git a/src/midiMessage/index.ts b/src/midiMessage/index.ts index 323f131..fa17eed 100644 --- a/src/midiMessage/index.ts +++ b/src/midiMessage/index.ts @@ -1,15 +1,15 @@ import { - BaseMessage, - ExpMessage, - SmartMessage, + RawMessage, + RawExpMessage, + RawSmartMessage, SmartMessageType, -} from '../types/Messages'; -import { MidiMessageType, ParsedExpMessage, ParsedMessage, ParsedSmartMessage, -} from './types'; + SwitchSide, + FlexiPart, +} from '../types'; import { convertTypeAndChannelToStatusByte, convertStatusByteToType, @@ -25,11 +25,14 @@ import { } from './midiHexHelpers'; import { isExpressionMidiMessage, isSmartMidiMessage } from './guards'; -export function decodeMidiMessage(input: BaseMessage): ParsedMessage; -export function decodeMidiMessage(input: ExpMessage): ParsedExpMessage; -export function decodeMidiMessage(input: SmartMessage): ParsedSmartMessage; +/** + * Decodes a raw message from the device into a more usable format with human/device readable properties + */ +export function decodeMidiMessage(input: RawMessage): ParsedMessage; +export function decodeMidiMessage(input: RawExpMessage): ParsedExpMessage; +export function decodeMidiMessage(input: RawSmartMessage): ParsedSmartMessage; export function decodeMidiMessage( - message: BaseMessage | ExpMessage | SmartMessage + message: RawMessage | RawExpMessage | RawSmartMessage ): ParsedMessage | ParsedExpMessage | ParsedSmartMessage { if (isSmartMidiMessage(message)) { return decodeSmartMessage(message); @@ -45,7 +48,7 @@ export function decodeMidiMessage( } const decodeBaseMessage = ( - message: BaseMessage | ExpMessage + message: RawMessage | RawExpMessage ): ParsedMessage => { const type = convertStatusByteToType(message.statusByte); const channel = convertStatusByteToChannel(message.statusByte); @@ -97,7 +100,7 @@ const decodeBaseMessage = ( } }; -const decodeSmartMessage = (message: SmartMessage): ParsedSmartMessage => { +const decodeSmartMessage = (message: RawSmartMessage): ParsedSmartMessage => { const { dataByte1, dataByte2 } = message; // TODO: complete validation @@ -112,7 +115,9 @@ const decodeSmartMessage = (message: SmartMessage): ParsedSmartMessage => { type: MidiMessageType.SmartMessage, smartType: message.smartType, switchIndex: convertDataByteToNumber(dataByte1), - side: ['primary', 'secondary'][convertDataByteToNumber(dataByte2)], + side: [SwitchSide.Primary, SwitchSide.Secondary][ + convertDataByteToNumber(dataByte2) + ], }; case SmartMessageType.SequentialResetStep: case SmartMessageType.SequentialIncrementStep: @@ -172,21 +177,27 @@ const decodeSmartMessage = (message: SmartMessage): ParsedSmartMessage => { type: MidiMessageType.SmartMessage, smartType: message.smartType, flexiPort: convertDataByteToNumber(dataByte1), - part: ['None', 'Tip', 'Ring', 'TipRing'][ - convertDataByteToNumber(dataByte2) - ], + part: [ + FlexiPart.None, + FlexiPart.Tip, + FlexiPart.Ring, + FlexiPart.TipRing, + ][convertDataByteToNumber(dataByte2)], }; default: throw new Error('unhandled smart type'); } }; -export function encodeMidiMessage(input: ParsedMessage): BaseMessage; -export function encodeMidiMessage(input: ParsedExpMessage): ExpMessage; -export function encodeMidiMessage(input: ParsedSmartMessage): SmartMessage; +/** + * Encodes the easy-to-use format back into a raw device message + */ +export function encodeMidiMessage(input: ParsedMessage): RawMessage; +export function encodeMidiMessage(input: ParsedExpMessage): RawExpMessage; +export function encodeMidiMessage(input: ParsedSmartMessage): RawSmartMessage; export function encodeMidiMessage( message: ParsedMessage | ParsedExpMessage | ParsedSmartMessage -): BaseMessage | ExpMessage | SmartMessage { +): RawMessage | RawExpMessage | RawSmartMessage { switch (message.type) { case MidiMessageType.ProgramChange: case MidiMessageType.ChannelPressure: { @@ -234,7 +245,7 @@ export function encodeMidiMessage( } } -const encodeSmartMessage = (message: ParsedSmartMessage): SmartMessage => { +const encodeSmartMessage = (message: ParsedSmartMessage): RawSmartMessage => { const common = { smartType: message.smartType, statusByte: '70' }; switch (message.smartType) { @@ -245,7 +256,7 @@ const encodeSmartMessage = (message: ParsedSmartMessage): SmartMessage => { ...common, dataByte1: convertNumberToDataByte(message.switchIndex), dataByte2: convertNumberToDataByte( - { primary: 0, secondary: 1 }[message.side] + { [SwitchSide.Primary]: 0, [SwitchSide.Secondary]: 1 }[message.side] ), }; case SmartMessageType.SequentialResetStep: @@ -301,7 +312,12 @@ const encodeSmartMessage = (message: ParsedSmartMessage): SmartMessage => { ...common, dataByte1: convertNumberToDataByte(message.flexiPort), dataByte2: convertNumberToDataByte( - { None: 0, Tip: 1, Ring: 2, TipRing: 3 }[message.part] + { + [FlexiPart.None]: 0, + [FlexiPart.Tip]: 1, + [FlexiPart.Ring]: 2, + [FlexiPart.TipRing]: 3, + }[message.part] ), }; } diff --git a/src/midiMessage/midiHexHelpers.ts b/src/midiMessage/midiHexHelpers.ts index 8f07ef0..426036e 100644 --- a/src/midiMessage/midiHexHelpers.ts +++ b/src/midiMessage/midiHexHelpers.ts @@ -2,7 +2,8 @@ * Massive thanks to Pirate MIDI and Kurtis Simpson for sharing their conversion methods */ -import { MidiMessageType } from './types'; +import { MidiMessageType } from '../types'; +import { isMidiMessageType } from './guards'; // Two arrays allow us to map key<->value in either direction const types = [ @@ -36,6 +37,8 @@ export function convertTypeAndChannelToStatusByte( type: string, channel: number ): string { + if (!isMidiMessageType(type)) throw new Error(`type "${type}" is not valid`); + const firstHex: string = typeByteValues[types.indexOf(type)]; const secondHex: string = (channel - 1).toString(16); diff --git a/src/midiMessage/types/index.ts b/src/midiMessage/types/index.ts deleted file mode 100644 index 8c84031..0000000 --- a/src/midiMessage/types/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { MidiMessageType } from './MidiMessageType'; -export { ParsedExpMessage, ParsedMessage } from './Message'; -export { ParsedSmartMessage } from './SmartMessage'; diff --git a/src/types/BankSettings.ts b/src/types/BankSettings.ts index 9e8e9e2..01746aa 100644 --- a/src/types/BankSettings.ts +++ b/src/types/BankSettings.ts @@ -1,11 +1,12 @@ -import { AuxMessages, ExpMessage, MessageStack } from './Messages'; +import { RawExpMessage } from './RawMessage'; +import { AuxMessages, MessageStack } from './MessageStack'; // Extend Record to help infer the runCommand type export interface BankSettings extends Record { bankName: string; bankId: string; // 32-bit bankMessages: MessageStack; - expMessages: MessageStack[]; + expMessages: MessageStack[]; switchGroups: Array; auxMessages: AuxMessages[]; footswitches: Footswitch[]; diff --git a/src/types/GlobalSettings.ts b/src/types/GlobalSettings.ts index cb2714c..a863cf1 100644 --- a/src/types/GlobalSettings.ts +++ b/src/types/GlobalSettings.ts @@ -1,5 +1,6 @@ import { EnabledMidiOuts } from './EnabledMidiOuts'; -import { AuxMessages, ExpMessage, MessageStack } from './Messages'; +import { RawExpMessage } from './RawMessage'; +import { MessageStack, AuxMessages } from './MessageStack'; // Extend Record to help infer the runCommand type export interface GlobalSettings extends Record { @@ -21,7 +22,7 @@ export interface GlobalSettings extends Record { flexi2ThruHandles: EnabledMidiOuts; midi0ThruHandles: EnabledMidiOuts; usbThruHandles: EnabledMidiOuts; - expMessages: MessageStack[]; + expMessages: MessageStack[]; auxMessages: AuxMessages[]; } diff --git a/src/midiMessage/types/Message.ts b/src/types/Message.ts similarity index 93% rename from src/midiMessage/types/Message.ts rename to src/types/Message.ts index 2fdfd05..5e2a887 100644 --- a/src/midiMessage/types/Message.ts +++ b/src/types/Message.ts @@ -1,5 +1,5 @@ -import { EnabledMidiOuts } from '../../types/EnabledMidiOuts'; -import { ExpressionParameters } from '../../types/Messages'; +import { EnabledMidiOuts } from './EnabledMidiOuts'; +import { ExpressionParameters } from './RawMessage'; import { MidiMessageType } from './MidiMessageType'; interface Base { diff --git a/src/types/MessageStack.ts b/src/types/MessageStack.ts new file mode 100644 index 0000000..0836b13 --- /dev/null +++ b/src/types/MessageStack.ts @@ -0,0 +1,17 @@ +import { RawMessage } from './RawMessage'; + +export interface MessageStack { + numMessages: number; + messages: Message[]; +} + +export interface AuxMessages { + tip: AuxMessageStacks; + ring: AuxMessageStacks; + tipRing: AuxMessageStacks; +} + +export interface AuxMessageStacks { + pressMessages: MessageStack; + holdMessages: MessageStack; +} diff --git a/src/midiMessage/types/MidiMessageType.ts b/src/types/MidiMessageType.ts similarity index 100% rename from src/midiMessage/types/MidiMessageType.ts rename to src/types/MidiMessageType.ts diff --git a/src/types/RawMessage.ts b/src/types/RawMessage.ts new file mode 100644 index 0000000..dc1872e --- /dev/null +++ b/src/types/RawMessage.ts @@ -0,0 +1,24 @@ +import { EnabledMidiOuts } from './EnabledMidiOuts'; +import { SmartMessageType } from './SmartMessageType'; + +export interface ExpressionParameters { + minLimit: number; + maxLimit: number; + sweep: 'linear' | 'log' | 'reverseLog'; +} + +export interface RawMessage { + statusByte: string; // 8-bit hex + dataByte1: string; // 8-bit hex + dataByte2?: string; // 8-bit hex + outputs: EnabledMidiOuts; +} + +export interface RawSmartMessage { + statusByte: string; // 8-bit hex + dataByte1: string; // 8-bit hex + dataByte2?: string; // 8-bit hex + smartType: SmartMessageType; +} + +export interface RawExpMessage extends RawMessage, ExpressionParameters {} diff --git a/src/midiMessage/types/SmartMessage.ts b/src/types/SmartMessage.ts similarity index 88% rename from src/midiMessage/types/SmartMessage.ts rename to src/types/SmartMessage.ts index f0aac40..a20c3ac 100644 --- a/src/midiMessage/types/SmartMessage.ts +++ b/src/types/SmartMessage.ts @@ -1,5 +1,17 @@ import { MidiMessageType } from './MidiMessageType'; -import { SmartMessageType } from '../../types/Messages'; +import { SmartMessageType } from './SmartMessageType'; + +export enum SwitchSide { + Primary = 'Primary', + Secondary = 'Secondary', +} + +export enum FlexiPart { + None = 'None', + Tip = 'Tip', + Ring = 'Ring', + TipRing = 'TipRing', +} export interface SmartSwitchMessage { type: MidiMessageType.SmartMessage; @@ -8,7 +20,7 @@ export interface SmartSwitchMessage { | SmartMessageType.SwitchOff | SmartMessageType.SwitchToggle; switchIndex: number; - side: 'primary' | 'secondary'; + side: SwitchSide; } export interface SmartSequentialMessage { @@ -66,7 +78,7 @@ export interface SmartTrsMessage { type: MidiMessageType.SmartMessage; smartType: SmartMessageType.TrsSwitchOut | SmartMessageType.TrsPulseOut; flexiPort: number; - part: 'None' | 'Tip' | 'Ring' | 'TipRing'; + part: FlexiPart; } export type ParsedSmartMessage = diff --git a/src/types/Messages.ts b/src/types/SmartMessageType.ts similarity index 51% rename from src/types/Messages.ts rename to src/types/SmartMessageType.ts index 582953b..35156d7 100644 --- a/src/types/Messages.ts +++ b/src/types/SmartMessageType.ts @@ -1,25 +1,3 @@ -import { EnabledMidiOuts } from './EnabledMidiOuts'; - -export interface MessageStack { - numMessages: number; - messages: Message[]; -} - -export interface BaseMessage { - statusByte: string; // 8-bit hex - dataByte1: string; // 8-bit hex - dataByte2?: string; // 8-bit hex - outputs: EnabledMidiOuts; -} - -export interface ExpressionParameters { - minLimit: number; - maxLimit: number; - sweep: 'linear' | 'log' | 'reverseLog'; -} - -export interface ExpMessage extends BaseMessage, ExpressionParameters {} - export enum SmartMessageType { SwitchOn = 'switchOn', SwitchOff = 'switchOff', @@ -45,21 +23,3 @@ export enum SmartMessageType { TrsSwitchOut = 'trsSwitchOut', TrsPulseOut = 'trsPulseOut', } - -export interface SmartMessage { - statusByte: string; // 8-bit hex - dataByte1: string; // 8-bit hex - dataByte2?: string; // 8-bit hex - smartType: SmartMessageType; -} - -export interface AuxMessages { - tip: AuxMessageStacks; - ring: AuxMessageStacks; - tipRing: AuxMessageStacks; -} - -export interface AuxMessageStacks { - pressMessages: MessageStack; - holdMessages: MessageStack; -} diff --git a/src/types/index.ts b/src/types/index.ts index c110b0e..7444c51 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,9 +1,16 @@ import { PirateMidiDevice } from '../PirateMidiDevice'; +export * from './BankSettings'; export * from './Commands'; export * from './DeviceInfo'; +export * from './EnabledMidiOuts'; export * from './GlobalSettings'; -export * from './BankSettings'; +export * from './Message'; +export * from './MessageStack'; +export * from './MidiMessageType'; +export * from './RawMessage'; +export * from './SmartMessage'; +export * from './SmartMessageType'; /** * Default export diff --git a/tsconfig.json b/tsconfig.json index 56fb7ec..09cf8c3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,7 +20,7 @@ "./types" ], "paths": { - "*" : ["types/*"] + "*" : ["./types/*"] } }, "include": ["src/**/*.ts", "scripts/**/*.ts"],