123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- //
- // main.m
- // DHSendMIDI
- //
- // Created by Douglas Heriot on 23/01/13.
- // Copyright (c) 2013 Douglas Heriot. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- #import <SnoizeMIDI/SnoizeMIDI.h>
- #include <getopt.h>
- enum OPTION
- {
- O_VERSION = 'V',
- O_HELP = 'h',
-
- O_CHANNEL = 'c',
- O_DESTINATION = 'd',
- O_VERBOSE = 'v',
-
- O_NOTE_OFF = 'm',
- O_NOTE_ON = 'n',
- O_AFTERTOUCH = 'a',
- O_CONTROL_CHANGE = 'r',
- O_PROGRAM_CHANGE = 'p',
- O_CHANNEL_PRESSURE = 's',
- O_PITCH_WHEEL = 'w',
- };
- void printVersion(void);
- void printHelp(void);
- int main(int argc, char * const *argv)
- {
- @autoreleasepool
- {
- SMVoiceMessageStatus messageStatus = SMVoiceMessageStatusControl;
- Byte channel = 1;
- uint8_t data[2] = {0};
- NSString *destination = nil;
- BOOL verbose = NO;
-
- static struct option longOoptions[] = {
- {"version", no_argument, NULL, O_VERSION},
- {"help", no_argument, NULL, O_HELP},
-
- {"channel", required_argument, NULL, 'c'},
- {"destination", required_argument, NULL, 'd'},
- {"verbose", no_argument, NULL, 'v'},
-
- {"note-off", no_argument, NULL, O_NOTE_OFF},
- {"note-on", no_argument, NULL, O_NOTE_ON},
- {"aftertouch", no_argument, NULL, O_AFTERTOUCH},
- {"control-change", no_argument, NULL, O_CONTROL_CHANGE},
- {"control", no_argument, NULL, O_CONTROL_CHANGE},
- {"cc", no_argument, NULL, O_CONTROL_CHANGE},
- {"program-change", no_argument, NULL, O_PROGRAM_CHANGE},
- {"program", no_argument, NULL, O_PROGRAM_CHANGE},
- {"pc", no_argument, NULL, O_PROGRAM_CHANGE},
- {"channel-pressure",no_argument, NULL, O_CHANNEL_PRESSURE},
- {"pressure", no_argument, NULL, O_CHANNEL_PRESSURE},
- {"pitch-wheel", no_argument, NULL, O_PITCH_WHEEL},
- {"pitch", no_argument, NULL, O_PITCH_WHEEL},
- };
- const char shortOptions[] = {
- O_VERSION, O_HELP,
- O_CHANNEL, ':', O_DESTINATION, ':', O_VERBOSE,
- O_NOTE_ON, O_NOTE_OFF, O_AFTERTOUCH, O_CONTROL_CHANGE, O_PROGRAM_CHANGE, O_CHANNEL_PRESSURE, O_PITCH_WHEEL,
- '\0'};
-
- int ch;
- while((ch = getopt_long(argc, argv, shortOptions, longOoptions, NULL)) != -1)
- {
- switch ((enum OPTION)ch)
- {
- case O_VERSION:
- printVersion();
- exit(0);
- break;
-
- case O_HELP:
- printVersion();
- printHelp();
- exit(0);
- break;
-
- case O_CHANNEL:
- channel = atoi(optarg);
-
- if(channel == 0)
- channel = 1; // you probably meant 1
-
- // Make sure it’s within bounds 1-16
- channel -= 1;
- channel %= 16;
- channel += 1;
- break;
-
- case O_DESTINATION:
- destination = [NSString stringWithUTF8String:optarg];
- break;
-
- case O_VERBOSE:
- verbose = YES;
- break;
-
- case O_NOTE_ON:
- messageStatus = SMVoiceMessageStatusNoteOn;
- break;
- case O_NOTE_OFF:
- messageStatus = SMVoiceMessageStatusNoteOff;
- break;
- case O_AFTERTOUCH:
- messageStatus = SMVoiceMessageStatusAftertouch;
- break;
- case O_CONTROL_CHANGE:
- messageStatus = SMVoiceMessageStatusControl;
- break;
- case O_PROGRAM_CHANGE:
- messageStatus = SMVoiceMessageStatusProgram;
- break;
- case O_CHANNEL_PRESSURE:
- messageStatus = SMVoiceMessageStatusChannelPressure;
- break;
- case O_PITCH_WHEEL:
- messageStatus = SMVoiceMessageStatusPitchWheel;
- break;
- }
- }
-
- argc -= optind;
- argv += optind;
-
-
- // Create the message
- SMVoiceMessage *message = [[SMVoiceMessage alloc] initWithTimeStamp:0 statusByte:messageStatus];
- [message setTimeStampToNow];
- [message setChannel:channel];
-
- const NSUInteger requiredLength = message.otherDataLength;
-
- // Check the given arguments
- if(argc != requiredLength)
- {
- const char s[] = {requiredLength == 1 ? '\0' : 's', '\0'};
- fprintf(stderr, "%s message must have %lu argument%s\n", message.typeForDisplay.UTF8String, requiredLength, s);
-
- return 1;
- }
-
-
- // Get the arguments
- // Make sure they’re within 0-127, by &ing with 0x7F
-
- data[0] = atoi(argv[0]) & 0x7F;
- [message setDataByte1:data[0]];
-
- if(requiredLength > 1)
- {
- data[1] = atoi(argv[1]) & 0x7F;
- [message setDataByte2:data[1]];
- }
-
-
- SMPortOutputStream *os = [[SMPortOutputStream alloc] init];
-
- // Set the destination endpoints
- NSSet *endpoints = nil;
-
- if(destination)
- endpoints = [NSSet setWithObject:[SMDestinationEndpoint destinationEndpointWithName:destination]];
- else
- endpoints = [NSSet setWithArray:[SMDestinationEndpoint destinationEndpoints]];
-
- [os setEndpoints:endpoints];
-
-
- // Send the message
- [os takeMIDIMessages:@[message]];
-
-
- if(verbose)
- {
- printf("Sent %s: %d", message.typeForDisplay.UTF8String, data[0]);
- if([message otherDataLength] > 1)
- printf(" %d", data[1]);
- printf("\n");
- }
- }
- return 0;
- }
- void printVersion(void)
- {
- printf("DHSendMIDI 1.0\nCopyright 2013, Douglas Heriot\nhttps://github.com/DouglasHeriot/DHSendMIDI\n");
- }
- void printHelp(void)
- {
- printf("\n"
- "Usage: DHSendMIDI [options] byte1 [byte2]\n\n"
- "Options:\n"
- " --note-on, -n Note On\n"
- " --note-off, -m Note Off\n"
- " --aftertouch, -a Aftertouch\n"
- " --control-change, --cc, -c Control Change\n"
- " --program-change, --pc, p Program Change (only 1 byte of data)\n"
- " --channel-pressure, --pressure, -s Channel Pressure (only 1 byte of data)\n"
- " --pitch-wheel, --pitch, -w Pitch Wheel (2 bytes, making a 14-bit value)\n"
- "\n"
- " --channel, -c Channel 1-16\n"
- " --destination, -d Destination device\n"
- " Example: to send to IAC Driver, Bus 1, use\n"
- " --destination \"Bus 1\"\n"
- " Defaults to all destinations\n"
- "\n"
- " --verbose, -v Prints message being sent\n"
- "\n"
- " --version, -V Displays version\n"
- " --help, -h Displays this help\n"
- "\n"
- "Without any options, DHSendMIDI defaults to control change messages, on channel 1, to all destinations.\n"
- "\n");
- }
|