Search code examples
perlhexmessagingmidiunpack

How to send MIDI messages in Perl?


I am trying to send MIDI messages using Perl. Basically I want to change the patch instrument. Since I am not generating a file, but playing only, I am using Win32::MIDI as it is the only module that works for what I require, but there is no module patch instrument method, therefore I am left with writeMIDI which requires sending it a MIDI message.

eg.

...
# note_on event, channel 1 (0x90), velocity (127), note (127), null (0x00);
my $data_on = "\x00\127\127\x90";     
# note_off event, channel 1 (0x80), velocity (127), note (127), null (0x00);
my $data_off  = "\x00\127\127\x80";

$midi_obj->writeMIDI(unpack("N",$data_on));
sleep(2);
$midi_obj->writeMIDI(unpack("N",$data_off));

$midi_obj->writeMIDI(unpack("N","\x00\C18")); <-- NOT WORKING change instrument on channel # 1 to patch # 8

I am trying to do a 'Program Change' on Channel 1, patch no# (eg. 8) as this changes the patch instrument.

as it says in my reference:

A.1. Channel voice messages:

Instruct the receiving instrument to assign particular sounds to its voice Turn notes on and off Alter the sound of the currently active note or notes


Voice Message         Status Byte     Data Byte1         Data Byte2
Note off                      8x      Key number          Note Off velocity
Note on                       9x      Key number          Note on velocity
Polyphonic Key Pressure       Ax      Key number          Amount of pressure
Control Change                Bx      Controller number   Controller value

Program Change Cx Program number None
Channel Pressure Dx Pressure value None Pitch Bend Ex MSB LSB Notes: `x' in status byte hex value stands for a channel number.

Reference I am using https://users.cs.cf.ac.uk/Dave.Marshall/Multimedia/node158.html


Solution

  • unpack("N","\x00\C18\7F")

    This does not look correct, there is no string escape \C. Also if you were trying to write an octal escape, still C18 and 7F would not be octal numbers. Please clarify what you are trying to write in hex.

    Some more information on octal escapes can be found in perlop:

    \033

    The result is the character specified by the three-digit octal number in the range 000 to 777 (but best to not use above 077, see next paragraph)

    Some contexts allow 2 or even 1 digit, but any usage without exactly three digits, the first being a zero, may give unintended results. (For example, in a regular expression it may be confused with a backreference; see "Octal escapes" in perlrebackslash.) Starting in Perl 5.14, you may use \o{} instead, which avoids all these problems. Otherwise, it is best to use this construct only for ordinals \077 and below, remembering to pad to the left with zeros to make three digits. For larger ordinals, either use \o{}, or convert to something else, such as to hex and use \N{U+} (which is portable between platforms with different character sets) or \x{} instead.

    Update:

    I am trying to do a 'Program Change', as this changes the patch instrument.

    According to this and this you could try something like this:

    my $channel_number = 1;
    my $program_number = 15;
    my $unused = 0;
    my $str = pack("CCCC", $unused, $unused, $program_number, $channel_number+0xC0);
    $midi_obj->writeMIDI(unpack("N",$str));