PSMidi.psm1
|
#region PreCode _PreModule_Requires #Requires -Modules @{ ModuleName = 'WindowsMidiServices'; ModuleVersion = '0.0.1' } #endregion PreCode _PreModule_Requires #region Classes enum NoteIndex { C = 0 D = 2 E = 4 F = 5 G = 7 A = 9 B = 11 H = 11 } Class Chord { [string] $BaseChord [int] $Octave [string] $Alt hidden [int] $AltMidi [int] $MidiNote Chord($Chord) { $null = $Chord -match '^(?<BaseNote>[a-gA-G])(?<Alt>[#b]?)(?<Octave>(-?[1-2]|[0-8])$)' $this.BaseChord = $Matches['BaseNote'].ToUpper() $this.Alt = $Matches['Alt'] ?? [string]::Empty $this.AltMidi = $Matches['Alt'] -eq 'b' ? [int]-1 : $Matches['Alt'] -eq '#' ? 1 : 0 $this.Octave = $Matches['Octave'] $this.MidiNote = ( ([NoteIndex]$Matches['BaseNote'].ToUpper()).value__ + $this.AltMidi ) + ( ([int]$Matches['Octave'] + 2) * 12) } } #endregion Classes #region Get-PSNoteIndexFromNoteName Function Get-PSNoteIndexFromNoteName { [CmdletBinding()] Param( [Parameter()] [ValidatePattern('^[a-gA-G][#b]?(-?[1-2]|[0-8])$', ErrorMessage = 'Input must match pattern <note><octave>')] [string]$NoteName ) [chord]::new($NoteName) } #endregion Get-PSNoteIndexFromNoteName #region New-PSMidiMessage Function New-PSMidiMessage { [CmdletBinding(DefaultParameterSetName = 'Note')] Param( [Parameter(ParameterSetName = 'Note')] [Parameter(ParameterSetName = 'Pitch')] [ValidateSet('C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B')] [String]$Note = 'C', [Parameter(ParameterSetName = 'Note')] [Parameter(ParameterSetName = 'Pitch')] [ValidateRange(0, 9)] [int]$Octave = 3, [Parameter(ParameterSetName = 'Note')] [Parameter(ParameterSetName = 'Pitch')] [ValidateRange(0, 15)] [int]$Group = 0, [Parameter(ParameterSetName = 'Note')] [Parameter(ParameterSetName = 'Pitch')] [Microsoft.Windows.Devices.Midi2.Messages.Midi2ChannelVoiceMessageStatus]$MessageStatus = 'NoteOn', [Parameter(ParameterSetName = 'Note')] [Parameter(ParameterSetName = 'Pitch')] [ValidateRange(0, 15)] [int]$MidiChannel = 0, [Parameter(ParameterSetName = 'Note')] [Parameter(ParameterSetName = 'Pitch')] [ValidateRange(0, 65535)] [uint]$Velocity = 65535, [Parameter(ParameterSetName = 'Pitch')] [switch]$Pitch, [Parameter(ParameterSetName = 'Pitch')] [ValidateRange(0, 65535)] [int]$AttributeData ) if ($PSBoundParameters.Keys.Contains('Pitch')) { $attributeType = 3 } else { $attributeType = 0 $AttributeData = 0 } $Chord = [Chord]::new("${Note}${Octave}") $playNote = ($Chord.MidiNote -shl 8) -bor $attributeType [uint]$messageData = ($Velocity -shl 16) -bor $AttributeData [Microsoft.Windows.Devices.Midi2.Messages.MidiMessageBuilder]::BuildMidi2ChannelVoiceMessage( ((Get-Date).ToFileTimeUtc()), [Microsoft.Windows.Devices.Midi2.MidiGroup]::new($Group), $MessageStatus, [Microsoft.Windows.Devices.Midi2.MidiChannel]::new($MidiChannel), $playNote, $messageData ) } #endregion New-PSMidiMessage #region Send-PSMidiMessage Function Send-PSMidiMessage { Param( [Parameter(Mandatory)] [WindowsMidiServices.MidiEndpointConnection]$Connection, [Parameter(Mandatory, ValueFromPipeline)] [Microsoft.Windows.Devices.Midi2.MidiMessage64]$Message ) Send-MidiMessage -Connection $Connection -Words $($Message.Word0, $Message.Word1) } #endregion Send-PSMidiMessage |