CoreMidi.framework sending midi commands - objective-c

there is an app called FreeStyler, that you can control using midi commands. In my mac app I want to send midi signals.
Can someone show an example of this?
Elijah

This is what it took to send a note to my blofeld synth. I hope it helps. You can use MIDIObjectGetProperties to find the uniqueIDs for all the midi devices connected to your mac.
#import <Foundation/Foundation.h>
#import <CoreMIDI/CoreMIDI.h>
MIDIEndpointRef getEndpointWithUniqueID(MIDIUniqueID id){
MIDIObjectRef endPoint;
MIDIObjectType foundObj;
MIDIObjectFindByUniqueID(id, &endPoint, &foundObj);
return (MIDIEndpointRef) endPoint;
}
MIDIClientRef getMidiClient(){
MIDIClientRef midiClient;
NSString *outPortName =#"blofeldOut";
MIDIClientCreate((CFStringRef)outPortName, NULL, NULL, &midiClient);
return midiClient;
}
MIDIPortRef getOutPutPort(){
MIDIPortRef outPort;
NSString *outPortName =#"blofeldOut";
MIDIOutputPortCreate(getMidiClient(), (CFStringRef)outPortName, &outPort);
return outPort;
}
MIDIPacketList getMidiPacketList(){
MIDIPacketList packetList;
packetList.numPackets = 1;
MIDIPacket* firstPacket = &packetList.packet[0];
firstPacket->timeStamp = 0; // send immediately
firstPacket->length = 3;
firstPacket->data[0] = 0x90;
firstPacket->data[1] = 60;
firstPacket->data[2] = 64;
// TODO: add end note sequence
return packetList;
}
void play_note(void) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
MIDIPacketList packetList=getMidiPacketList();
MIDIUniqueID blofeldEndpointID = -934632258;
MIDIEndpointRef blofeldEndpoint = getEndpointWithUniqueID(blofeldEndpointID);
MIDISend(getOutPutPort(), blofeldEndpoint, &packetList);
MIDIEndpointDispose(blofeldEndpoint);
[pool drain];
}
int main (int argc, const char * argv[]) {
play_note();
return 0;
}

Your application will need to use the CoreMIDI framework to send or receive MIDI, which I can tell you from experience is not a lot of fun to work with directly. You might want to try the vvopensource framework, which is a MIDI framework designed for cocoa.

Related

Setting media playback info in MacOs not working

I'm a newbie in ObjC and MacOs development.
My final goal is understand how setting playback info works from ObjC to try to implement that later on Rust (using generated ObjC runtime bindings).
So right now I'm trying to write small piece of code on ObjC that would set playback info (without actually playing anything).
I have found https://github.com/MarshallOfSound/electron-media-service/blob/master/src/darwin/service.mm and used it as a base.
Here's code I have right now:
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import <objc/runtime.h>
#include "MediaPlayer/MPNowPlayingInfoCenter.h"
#include "MediaPlayer/MPRemoteCommandCenter.h"
#include "MediaPlayer/MPRemoteCommand.h"
#include "MediaPlayer/MPMediaItem.h"
#include "MediaPlayer/MPRemoteCommandEvent.h"
#interface NativeMediaController : NSObject { }
#end
#implementation NativeMediaController
- (MPRemoteCommandHandlerStatus)remotePlay {
NSLog(#"Play");
return MPRemoteCommandHandlerStatusSuccess;
}
- (MPRemoteCommandHandlerStatus)remotePause {
NSLog(#"Pause");
return MPRemoteCommandHandlerStatusSuccess;
}
- (MPRemoteCommandHandlerStatus)remoteTogglePlayPause {
NSLog(#"PlayPause");
return MPRemoteCommandHandlerStatusSuccess;
}
- (MPRemoteCommandHandlerStatus)remoteNext {
NSLog(#"Next");
return MPRemoteCommandHandlerStatusSuccess;
}
- (MPRemoteCommandHandlerStatus)remotePrev {
NSLog(#"Previous");
return MPRemoteCommandHandlerStatusSuccess;
}
- (MPRemoteCommandHandlerStatus)remoteChangePlaybackPosition:(MPChangePlaybackPositionCommandEvent*)event {
NSLog(#"ChangePlaybackPosition");
return MPRemoteCommandHandlerStatusSuccess;
}
- (MPRemoteCommandHandlerStatus)move:(MPChangePlaybackPositionCommandEvent*)event {
NSLog(#"Move");
return MPRemoteCommandHandlerStatusSuccess;
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
NSLog(#"Hello, World!");
NativeMediaController* controller = [[NativeMediaController alloc] init];
MPRemoteCommandCenter *remoteCommandCenter = [MPRemoteCommandCenter sharedCommandCenter];
[remoteCommandCenter playCommand].enabled = true;
[remoteCommandCenter pauseCommand].enabled = true;
[remoteCommandCenter togglePlayPauseCommand].enabled = true;
[remoteCommandCenter changePlaybackPositionCommand].enabled = true;
[remoteCommandCenter nextTrackCommand].enabled = true;
[remoteCommandCenter previousTrackCommand].enabled = true;
[[remoteCommandCenter playCommand] addTarget:controller action:#selector(remotePlay)];
[[remoteCommandCenter pauseCommand] addTarget:controller action:#selector(remotePause)];
[[remoteCommandCenter togglePlayPauseCommand] addTarget:controller action:#selector(remoteTogglePlayPause)];
[[remoteCommandCenter changePlaybackPositionCommand] addTarget:controller action:#selector(remoteChangePlaybackPosition:)];
[[remoteCommandCenter nextTrackCommand] addTarget:controller action:#selector(remoteNext)];
[[remoteCommandCenter previousTrackCommand] addTarget:controller action:#selector(remotePrev)];
NSMutableDictionary *songInfo = [[NSMutableDictionary alloc] init];
[songInfo setObject:[NSString stringWithUTF8String:"Test title"] forKey:MPMediaItemPropertyTitle];
[songInfo setObject:[NSString stringWithUTF8String:"Test artist"] forKey:MPMediaItemPropertyArtist];
[songInfo setObject:[NSString stringWithUTF8String:"Test albumtitle"] forKey:MPMediaItemPropertyAlbumTitle];
[songInfo setObject:[NSNumber numberWithFloat:60.0] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
[songInfo setObject:[NSNumber numberWithFloat:360.0] forKey:MPMediaItemPropertyPlaybackDuration];
[songInfo setObject:[NSNumber numberWithFloat:112233] forKey:MPMediaItemPropertyPersistentID];
[MPNowPlayingInfoCenter defaultCenter].playbackState = MPNowPlayingPlaybackStatePlaying;
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo];
NSLog(#"End!");
char input[50] = {0};
printf("Enter anything to quit: ");
scanf("%s", input);
}
return 0;
}
When this code is executed I see no effect in MacOs playing info widget.
Unfortunately right now I have no idea how to debug this or where can I find better ObjC example.
Finally, I found the reason that caused my problem playing with Apple Swift example.
There're two requirements to show playback widget (i didn't find them documented anywhere) that have been missing:
You should register a callback for at least one action (play, pause)
You should build your application as an App, not as Console. If your program is not shown in the dock as a running app - the playback widget wouldn't work.

How to change mouse settings programmatically in macOS using IOKit

The functions IOHIDGetAccelerationWithKey and IOHIDSetAccelerationWithKey are deprecated since macOS 10.12, therefore I am trying to implement the same using other IO*-methods.
I have never worked with IOKit, thus, all I can do is google for functions and try to get it to work.
Now I found this: Can't edit IORegistryEntry which has an example of how to change TrackpadThreeFingerSwipe property, however it is using a function which is not defined for me: getEVSHandle. Googling for it reveals only that it should be Found in the MachineSettings framework, however I can't seem to add any "MachineSettings" framework in Xcode 11.
What should I do? Current code is like:
#import <Foundation/Foundation.h>
#import <IOKit/hidsystem/IOHIDLib.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSInteger value = -65536;
CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberNSIntegerType, &value);
CFMutableDictionaryRef propertyDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, NULL, NULL);
CFDictionarySetValue(propertyDict, #"HIDMouseAcceleration", number);
io_connect_t connect = getEVSHandle(); // ???
if (!connect)
{
NSLog(#"Unable to get EVS handle");
}
res = IOConnectSetCFProperties(connect, propertyDict);
if (res != KERN_SUCCESS)
{
NSLog(#"Failed to set mouse acceleration (%d)", res);
}
IOObjectRelease(service);
CFRelease(propertyDict);
}
return 0;
}
The following works (tested with Xcode 11.2 / macOS 10.15)
#import <Foundation/Foundation.h>
#import <IOKit/hidsystem/IOHIDLib.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
io_service_t service = IORegistryEntryFromPath(kIOMasterPortDefault,
kIOServicePlane ":/IOResources/IOHIDSystem");
NSDictionary *parameters = (__bridge NSDictionary *)IORegistryEntryCreateCFProperty(service,
CFSTR(kIOHIDParametersKey), kCFAllocatorDefault, kNilOptions);
NSLog(#"%#", parameters);
NSMutableDictionary *newParameters = [parameters mutableCopy];
newParameters[#"HIDMouseAcceleration"] = #(12345);
kern_return_t result = IORegistryEntrySetCFProperty(service,
CFSTR(kIOHIDParametersKey), (__bridge CFDictionaryRef)newParameters);
NSLog(kIOReturnSuccess == result ? #"Updated" : #"Failed");
IOObjectRelease(service);
}
return 0;
}

Watching for FileSystem Events on MacOS 10.10

I'm trying to code a little command line tool using Xcode (under MacOS 10.10) that watches a specific folder and informs me about changes to files in that folder.
I'm following the guide given in https://developer.apple.com/library/mac/documentation/Darwin/Conceptual/FSEvents_ProgGuide/UsingtheFSEventsFramework/UsingtheFSEventsFramework.html
Here is my current code:
#import <Foundation/Foundation.h>
#include <CoreServices/CoreServices.h>
void mycallback(
ConstFSEventStreamRef streamRef,
void *clientCallBackInfo,
size_t numEvents,
void *eventPaths,
const FSEventStreamEventFlags eventFlags[],
const FSEventStreamEventId eventIds[])
{
int i;
char **paths = eventPaths;
printf("Callback called\n");
for (i=0; i<numEvents; i++) {
int count;
/* flags are unsigned long, IDs are uint64_t */
printf("Change %llu in %s, flags %lu\n", eventIds[i], paths[i], eventFlags[i]);
}
}
int main(int argc, const char * argv[]) {
// #autoreleasepool {
// insert code here...
NSLog(#"Starting to watch ");
/* Define variables and create a CFArray object containing
CFString objects containing paths to watch.
*/
CFStringRef mypath = CFSTR("/Users/testuser/");
CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL);
void *callbackInfo = NULL; // could put stream-specific data here.
FSEventStreamRef stream;
CFAbsoluteTime latency = 3.0; /* Latency in seconds */
/* Create the stream, passing in a callback */
stream = FSEventStreamCreate(NULL,
&mycallback,
callbackInfo,
pathsToWatch,
kFSEventStreamEventIdSinceNow, /* Or a previous event ID */
latency,
kFSEventStreamCreateFlagNone /* Flags explained in reference */
);
/* Create the stream before calling this. */
FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(),kCFRunLoopDefaultMode);
FSEventStreamStart(stream);
CFRunLoopRun();
return 0;
}
The code compiles and can be started. However, no events are being fired. I'm pretty new to Xcode and also never ever used a callback function before. So I guess that this is a pretty dumb mistake that I made.
I'd appreciate any hints that may help.
Thanks in advance
Norbert
Update: The code was updated with a working solution from the answer.
According to the documentation, after starting event stream to send events, you should call CFRunLoopRun.
Try to change your while() loop to:
CFRunLoopRun();
Update. My output:
$ ./fsevent
2015-05-17 13:51:29.718 fsevent[898:23601] Starting to watch
Callback called
Change 1165579 in /Users/baf/src/tests/, flags 66560
Callback called
Change 1165594 in /Users/baf/src/tests/, flags 66048
It appears you have FSEventStreamRef stream; commented out. In order to start watching events you'll want to uncomment that line. It also looks like your callback print statement is also commented out, although that appears to be just for debugging perhaps.

Checking Objective-C block type?

This is primarily a curiosity, I'm not really sure what's the practical use of this but here goes.
Since blocks are also Objective-C objects, is it possible to check their type? That is, does it respond to the isKindOfClass: message and how to use that message with respect to blocks?
My naive thought that it's probably like this:
-(void) aMethod {
typedef int (^BlockA)(int x, int y);
id blockVar = ...; // get a block from somewhere
if([blockVar isKindOfClass:BlockA]) {
BlockA blockVarA = blockVar;
int result = blockVarA(1,2);
}
}
The code above probably won't work. But if it is possible to check a block's type, what is the correct way to do it?
Can do, kinda sorta.
But first, let's disambiguate. -[NSObject isKindOfClass:] can tell you it's a block, and that's about it. E.g. I believe this line of code -- ostensibly & unfortunately A BAD IDEA -- will return YES for blocks on present Lion & iOS 5.x:
[myBlock isKindOfClass:NSClassFromString(#"NSBlock")]
That won't help you distinguish the block's function signature.
But it can be done, by snagging the signature from the block's documented internal struct. Code follows for an example OS X command-line app, much of which ripped from Mike Ash's MABlockClosure (great detailed explanation). (UPDATE: Github project CTObjectiveCRuntimeAdditions also apparently provides library code for just this purpose.)
#import <Foundation/Foundation.h>
struct BlockDescriptor {
unsigned long reserved;
unsigned long size;
void *rest[1];
};
struct Block {
void *isa;
int flags;
int reserved;
void *invoke;
struct BlockDescriptor *descriptor;
};
static const char *BlockSig(id blockObj)
{
struct Block *block = (void *)blockObj;
struct BlockDescriptor *descriptor = block->descriptor;
int copyDisposeFlag = 1 << 25;
int signatureFlag = 1 << 30;
assert(block->flags & signatureFlag);
int index = 0;
if(block->flags & copyDisposeFlag)
index += 2;
return descriptor->rest[index];
}
int main(int argc, const char * argv[])
{
#autoreleasepool {
int (^block)(NSNumber *) = ^(NSNumber *num) {
NSLog(#"%# %#", NSStringFromClass([num class]), num);
return [num intValue];
};
NSLog(#"signature %s", BlockSig(block));
NSLog(#"retval %d", (int)block([NSNumber numberWithInt:42]));
}
return 0;
}
Run this and you should get something like:
[58003:403] signature i16#?0#8
[58003:403] __NSCFNumber 42
[58003:403] retval 42
The numbers in the signature (I'm told they are offsets) can be stripped for simpler i#?#.
The signature is in the #encode format, which isn't perfect (e.g. most objects map to same #), but should afford you some ability to distinguish blocks with different signatures at runtime.
While it's not documented in the Apple link, my testing points to #? being the code for a block type, which makes sense of the signature above. I found a clang-developers discussion on this issue which seems to back this up.
The "BlockA" in (^BlockA) is the variable name (in this case a typedef), not its class.
Blocks are objects, but not regular subclasses of NSObject. They only implement a subset of the methods. -isKindOfClass: will probably just crash.
Blocks are of the type NSMallocBlock or NSConcreteGlobalBlock, ... depending on where they were created (heap, stack, ...).
It seems that blocks are of classes like __NSGlobalBlock__, __NSStackBlock__, or __NSMallocBlock__, etc., whose inheritance chain eventually goes to NSBlock and then NSObject. So you could test whether something is a block by doing [... isKindOfClass:NSClassFromString(#"NSBlock")]. However, there doesn't seem to be any way to query a block's signature (return type and argument types) at runtime, so you wouldn't be able to distinguish between blocks of different signatures.
As well as Apple having nothing I can find to say on the matter, poking at a block with class_copyMethodList and method_getName reveals no obvious exposed methods. So I'm going to say that it isn't possible to check their type.
A old question, but anyway:
If you want a simple way of doing this: (Compile it with -fno-objc-arc)
Class __NSGlobalBlock__CLASS () {
static Class result = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dispatch_block_t thisIsAGlobalBlock = ^{// a block with no variables will be a __NSGlobalBlock__
};
result = [[thisIsAGlobalBlock class] retain];
});
return result;
};
Class __NSStackBlock__CLASS () {
static Class result = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
__block dispatch_block_t thisIsAStackBlock = ^{
return ;// we really DON'T want infinate recursion
thisIsAStackBlock();// including a reference to __block var makes this a __NSStackBlock__
};
result = [[thisIsAStackBlock class] retain];
});
return result;
};
Class __NSMallocBlock__CLASS () {
static Class result = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
__block dispatch_block_t thisIsAMallocBlock = Block_copy(// << turns the __NSStackBlock__ Block into a __NSMallocBlock__
^{
return ;// we really DON'T want infinate recursion
thisIsAMallocBlock();// including a reference to __block var makes this a __NSStackBlock__
});
result = [[thisIsAMallocBlock class] retain];
Block_release(thisIsAMallocBlock);
});
return result;
};
Test Code:
#autoreleasepool {
__block dispatch_block_t iAmAGlobalBlock = ^{
};
__block dispatch_block_t iAmAStackBlock = ^{
return;
iAmAStackBlock();
};
dispatch_block_t iAmHeapBlock = Block_copy(iAmAStackBlock);
dispatch_block_t iAmNotAHeapBlock = Block_copy(iAmAGlobalBlock);
if ([iAmAGlobalBlock isKindOfClass:__NSGlobalBlock__CLASS()]) {
NSLog(#"very great success!");
}
if ([iAmAStackBlock isKindOfClass:__NSStackBlock__CLASS()]) {
NSLog(#"another great success!");
}
if ([iAmHeapBlock isKindOfClass:__NSMallocBlock__CLASS()]) {
NSLog(#"also great success!");
}
if ([iAmNotAHeapBlock isKindOfClass:__NSGlobalBlock__CLASS()]) {
NSLog(#"yet another great success!");
}
NSLog (#"Block classes, as reported by NSStringFromClass():\n__NSGlobalBlock__CLASS() = %#\n__NSStackBlock__CLASS() = %#\n__NSMallocBlock__CLASS() = %#\n[iAmAGlobalBlock class] = %#\n[iAmAStackBlock class] = %#\n[iAmHeapBlock class] = %#\n[iAmNotAHeapBlock class] = %#\n",
NSStringFromClass(__NSGlobalBlock__CLASS()),
NSStringFromClass(__NSStackBlock__CLASS()),
NSStringFromClass(__NSMallocBlock__CLASS()),
NSStringFromClass([iAmAGlobalBlock class]),
NSStringFromClass([iAmAStackBlock class]),
NSStringFromClass([iAmHeapBlock class]),
NSStringFromClass([iAmNotAHeapBlock class])
);
Block_release(iAmHeapBlock);
Block_release(iAmNotAHeapBlock);// not really needed, but since we did "Block_copy" it...
}

Overriding main.m with run loop but still getting to the NSApplicationMain call?

Apologies if this is a stupid/easy question, but still getting used to everything in Mac land.
Dave was kind enough to answer a question for me here:
Modify NSEvent to send a different key than the one that was pressed
which resulted in the following code, which works great:
#import <Cocoa/Cocoa.h>
CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
//0x0b is the virtual keycode for "b"
//0x09 is the virtual keycode for "v"
if (CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode) == 0x0B) {
CGEventSetIntegerValueField(event, kCGKeyboardEventKeycode, 0x09);
}
return event;
}
int main(int argc, char *argv[]) {
//return NSApplicationMain(argc, (const char **)argv);
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
CFRunLoopSourceRef runLoopSource;
CFMachPortRef eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, kCGEventMaskForAllEvents, myCGEventCallback, NULL);
if (!eventTap) {
NSLog(#"Couldn't create event tap!");
exit(1);
}
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(eventTap, true);
CFRunLoopRun();
CFRelease(eventTap);
CFRelease(runLoopSource);
[pool release];
exit(0);
}
Thanks to some helpful error messages (can't have two "main" methods) I figured out that I had to put this code in the main.m file (right?). That means I'm overwriting the default method:
int main(int argc, char *argv[]) {
return NSApplicationMain(argc, (const char **)argv);
}
Which means none of my other Objective-C based code is firing. But if I uncomment that bit (or make any other attempt to call NSApplicationMain) then the main.m run loop is what doesn't run.
I imagine this is fairly simple for a seasoned Mac guy, but I'm having a hard time wrapping my head around it. Thanks.
I don't see any reason why the same idea won't work elsewhere in your code. Can you put it in the -applicationDidFinishLaunching: method of your app delegate? If you do, you will not need the CFRunLoop() call, since the run loop will already be running. Nor will you need the autorelease pool bit.