{"_id":"5509815f4ba6432d00bb7875","__v":14,"project":"55093b151c38c50d00611894","category":{"_id":"55093ef52ee8bf2b00491916","project":"55093b151c38c50d00611894","version":"55093b161c38c50d00611897","__v":9,"pages":["55094202961f17170070abbe","5509437a368a5617004146da","550963c0dd77250d007369c1","55096a172dd6a11900e6e774","5509811add77250d00736a1f","5509815f4ba6432d00bb7875","5509913ca2b4750d00a2341e","5509916add77250d00736a55","551923b0337285170047f861"],"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-03-18T09:01:41.604Z","from_sync":false,"order":3,"slug":"code-examples","title":"Code Examples"},"version":{"_id":"55093b161c38c50d00611897","project":"55093b151c38c50d00611894","__v":4,"createdAt":"2015-03-18T08:45:10.369Z","releaseDate":"2015-03-18T08:45:10.368Z","categories":["55093b161c38c50d00611898","55093ee2961f17170070abb9","55093ee9961f17170070abba","55093ef52ee8bf2b00491916"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.0.0","version":"1.0"},"user":"55093bd84510200d00adf3c7","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-18T13:45:03.014Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"auth":"required","params":[],"url":""},"isReference":false,"order":999,"body":"# MagicBeep #\n\nWelcome to _the second tutorial_ example !\n\nThis example presents the fundamental steps to master the ISKN API on Xcode for iOS. \nYou will learn how to connect to the slate, how to receive the slate events, \nand how to handle those events and get their parameters.\n\n\n\nThis is a simple sound player application using the ISKN Slate. \nThe application detects the presence of a pen  \nand plays a beep sound when the pen enters in the slate field of view.\nThe beep sounds depends on the pen colour.\n\nNote that you can find __the full source code__ for this example in the ISKN_API examples folder.   \n\n \n## 1.Set Up Your Project\n\nBefore you start, be sure you have your development environment set up.\nIn this example you need to create a __Single View Application__.\nYou can specify _MagicBeep_ as a project name.\n\nLink the ISKN API to your project. To do so you can see the first tutorial [here](getting-started-with-iskn-api-on-ios).\n\n\n \nIn addition to the ISKN API,you need to add three iOS frameworks to the application : CoreBluetooth.framework, UIKit.framework and AudioToolbox.framework.\n\nThe CoreBluetooth framework provides the resources your iOS apps need to communicate with devices\n that are equipped with Bluetooth low energy (BTLE) technology like the ISKN Slate.\n  \nThe UIKit framework (UIKit.framework) provides the crucial infrastructure needed to construct and manage iOS apps.\n \nThe AudioToolbox framework provides interfaces for recording, playback, and stream parsing.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/i5L3E0iNSJaRiH28J3Hi_Xcode_s2_Buildphases.png\",\n        \"Xcode_s2_Buildphases.png\",\n        \"880\",\n        \"297\",\n        \"#813817\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n+ Select the MagicBeep folder and right click on it.Select __New folder__ :\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/ZLhCuGXwQE6CfSMi2E9c_Xcode_s2_newFile.png\",\n        \"Xcode_s2_newFile.png\",\n        \"300\",\n        \"120\",\n        \"#2e64ab\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\nIn the left pane, select iOS then choose C++ file and click __Next__ :\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/S0QZGFqrQ6OytwEhpWvI_Xcode_s2_Add_cpp_File.png\",\n        \"Xcode_s2_Add_cpp_File.png\",\n        \"733\",\n        \"432\",\n        \"#1a3e7e\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n\nSpecify MagicBeep as a name and check __Also create a header file__ option then click __Next__ :\n\n\n\n:::at:::image html Xcode_s2_cppFile_options.png\n\n@image rtf Xcode_s2_cppFile_options.png \n\n@image latex Xcode_s2_cppFile_options.png \n\n@image docbook Xcode_s2_cppFile_options.png\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/8mjCGEBlR7GgxHcpA4a9_Xcode_s2_cppFile_options.png\",\n        \"Xcode_s2_cppFile_options.png\",\n        \"736\",\n        \"432\",\n        \"#3268ad\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\nSelect __Create__ on the next Window. Xcode generates a header file 'MagicBeep.h' and a source file 'MagicBeep.cpp' under the MagicBeep folder.\n\nNow your Project navigator should look like this :\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/l3i9qenT3uzVKowh11Q6_Xcode_s2_projectNavigator.png\",\n        \"Xcode_s2_projectNavigator.png\",\n        \"262\",\n        \"372\",\n        \"#2057a5\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\nDouble click on the MagicBeep.cpp file and change the extension from cpp to mm.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/4Y7wUMuSBirScLPQUrA2_Xcode_s2_projectNavigator2.png\",\n        \"Xcode_s2_projectNavigator2.png\",\n        \"262\",\n        \"372\",\n        \"#1c53a1\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n\nSince the ISKN API is a C++ library you need to mix C++ and Objective-C in the MagicBeep Files.\n\nBy renaming the MagicBeep.cpp file to have a .mm extension you tell the compiler that this file combine the Objective-C and the C++ languages.\n\n\n## 2.Including the ISKN API main header file\n\nAdd a Header Search Path for the ISKN API header. To do so you can see the first tutorial [here](md_src_example_ios_s1.html).\n\nInclude ISKN_API.h file in of the MagicBeep.h file  :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#include \\\"ISKN_API.h\\\"\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nSince the MagicBeep class should interact with both the graphical interface \nand the Audio service. We need to import the `AudioToolbox.h` file as well as\nthe `ViewController.h` file :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#import <AudioToolbox/AudioToolbox.h>\\n#import \\\"ViewController.h\\\"\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nCreate a C++ class with MagicBeep as name in the MagicBeep.h. \nThen add a reference to the ViewController class. \nThis reference is used to interact with the graphical interface :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"class MagicBeep \\n{\\n    \\npublic:\\n    MagicBeep(ViewController *viewController);\\n    \\n    ViewController *viewController;\\n};\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nIn the MagicBeep.mm, add MagicBeep constructor implementation.\nThe constructor takes as a parameter a pointer to a ViewController.\nIt saves this reference in the internal attribute viewController :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"MagicBeep::MagicBeep(ViewController *viewController)\\n{\\n    // Get a pointer to the view controller\\n    this->viewController=viewController;   \\n}\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\n\nThe viewController pointer allows access to the project ViewController.\n \n## 3.Preparing the event listener class\n\nTo receive the Slate events, you need to register a listener. \n\nIn this example, the MagicBeep class extends the Listener class.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"class MagicBeep : public Listener\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nThe listener class is an interface providing the following methods :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"void processEvent(ISKN_API::Event &e, unsigned int timecode);\\nvoid connectionStatusChanged(bool connected);\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nThose methods __should be implemented__ by the subclass in order to receive the slate events.\n\nAt this point, the MagicBeep listener class is ready to be registered.\n \n## 4.Preparing the communication tools\n\nBefore registering the listener, we need to create the Slate manager object.\n\nTo do so, add those attributes to your MagicBeep class declaration :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// ISKN API attributes\\n    SlateManager   *iskn_SlateManager;\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nIn the constructor method of the MagicBeep class, create the slate manager object :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"  // Create slate manager\\n    iskn_SlateManager  = new SlateManager();\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\n\n## 5. Registering the events listener\n\nOnce the slate manager, is created, it is possible to register the MagicBeep class as a listener. \n\nTo do so, use the registerListener method of the slate manager in MagicBeep constructor :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"//Register the MagicBeep class as a Listener\\n  \\tiskn_SlateManager->registerListener(this) ;\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n## 6. Connect to the slate and subscribe to the services\n\nBefore being able to receive slate events, the application should connect to the Slate.\n\nUse the `connect()` method of the Slate manager object to create a connection in the MagicBeep constructor :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \" //Send the connect command\\n    iskn_SlateManager->connect() ;\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nCheck if the connection succeeded by implementing the `connectionStatusChanged(bool)` method :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// Connection status has changed\\nvoid MagicBeep::connectionStatusChanged(bool connected)\\n{\\n    if(connected){\\n        // Request Slate description\\n        iskn_SlateManager.request(REQ_DESCRIPTION);\\n        \\n        // Subscribe to events (Status, Pen Status, Function Call and Pen_3D)\\n        \\n        iskn_SlateManager.subscribe(\\n                                 AUTO_STATUS |\\n                                 AUTO_SOFTWARE_EVENTS |\\n                                 AUTO_HARDWARE_EVENTS |\\n                                 AUTO_PEN_3D\\n                                 ) ;\\n                                     \\n        addTextToView(@\\\"[Connected]\\\\n\\\");\\n        NSLog(@\\\"[Connected]\\\\n\\\");\\n    }\\n    else\\n    {\\n        addTextToView(@\\\"[Could not connect]\\\\n\\\");\\n        NSLog(@\\\"[Could not connect]\\\\n\\\");\\n    }\\n}\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\n\nOnce connected, request the slate description in order to update the Device object information.\n\nThis gathers specific slate information such as slate name, the size of the slate, the writing zone of the slate.\nThis is performed by the request method of the Slate manager object.\n\nFinally, you need to subscribe to automatic events services. This tells the Slate which events your listener should receive.\n\n\nIn this application, we request four types of events :\n\n \n + AUTO_STATUS        \t\t: Asks to receive slate status changes (Battery charge change, (SD card insertion/ removal)).\n \n + AUTO_SOFTWARE_EVENTS    \t: Asks to receive Software events like object status change.\n (Object recognised (SE_OBJECT_IN), object lost(SE_OBJECT_OUT), handshake event (a periodic event used to detect that the Slate is still on)).\n \n + AUTO_HARDWARE_EVENTS \t: Asks to receive Hardware events (When a button is pressed (new page button, new layer button, reset event (long press on new page button)), SD card inserted or removed )\n \n + AUTO_PEN_2D        \t\t: Asks to receive the Pen tip 2D position and contact status at a 140Hz frequency when the pen is in the field of view of the slate.  \n\n\n## 7. Receive and extract events\n\nThe processEvent method is called whenever a new event is received from the Slate.\n\nUse the type attribute of the Event object in order to figure out the event type.\nYou can use a switch case statement as follow :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"switch (event.Type)\\n    {\\n        case EVT_STATUS :\\n        {\\n            //Slate status change detected\\n        }\\n            break ;\\n            \\n        case EVT_PEN_2D :\\n        {\\n            // New pen position and contact status\\n        }\\n            break ;\\n            \\n        case EVT_HARDWARE :\\n        {\\n   \\t\\t\\t//A hardware event happened \\n   \\t\\t\\tEventHardware &ev=event.HardwareEvent ;\\n            switch (ev.getHardwareEventType())\\n            {\\n                case HE_BUTTON1_PRESSED :\\n                     Button 1 is pressed\\n                    break ;\\n                case HE_BUTTON2_PRESSED :\\n                \\t Button 2 is pressed\\n                    break ;\\n                default :\\n                    break ;\\n            }\\n        }\\n            break ;\\n            \\n        case EVT_DESCRIPTION :\\n        {\\n        \\tEvent received after description request\\n        }\\n            break ;\\n            \\n            \\n        case EVT_SOFTWARE :\\n        {\\n        \\t//A software event has happened\\n        \\t\\n            EventSoftware &ev=event.SoftwareEvent ;\\n            \\n            switch (ev.getSoftwareEventType())\\n            {\\n                case SE_OBJECT_IN :\\n                {\\n                  // A new object is detected\\n                }\\n                    break ;\\n                case SE_OBJECT_OUT :\\n                {\\n                  // Object lost\\n                }\\n            }\\n        }\\n            break ;\\n            \\n        default :\\n        \\n            break ;\\n    }\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n## 8. Add a C wrapper to connect the objective-C and the C++\nIn order to link the view controller (Objective-C) to the MagicBeep class (C++),\nwe use C function Wrappers. \nThe first function `launchMagicBeep(ViewController *viewController)` is used to construct an instance of the MagicBeep class.\nThe instance is declared in the MagicBeep.mm source file:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"MagicBeep * magicBeep ;\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nThe wrapper function is preceded by the `extern \"C\"` statement in order to specify that it is a C function.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"extern \\\"C\\\"\\nvoid launchMagicBeep(ViewController *viewController)\\n{\\ntry\\n{\\nmagicBeep=new MagicBeep(viewController);\\n}\\ncatch (Error &err)\\n{\\nNSLog(@\\\"Error\\\");\\n}\\n}\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nThe wrapper function is called when the view is loaded.\nFirst in the `ViewController.m` file, add a prototype definition for the `launchMagicBeep` function.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"extern void launchMagicBeep(ViewController* viewController) ;\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nThen call `launchMagicBeep` in the viewDidLoad method of your ViewController :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"launchMagicBeep(self) ;\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nNow, the MagicBeep class has direct access to any synthesized property of the viewController.\n\n\n## 9. Preparing the Storyboard\n\nIn this application we use a simple interface with a `TextView`, a `Toolbar` with a single text item and an activity indicator to tell when the application is connecting to the Slate.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/r0RqdhU5QXuXT7UWjIWS_Xcode_s2_preparing_storyboard.png\",\n        \"Xcode_s2_preparing_storyboard.png\",\n        \"791\",\n        \"682\",\n        \"#224c8e\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\nCreate outlets for the TextView, the item and the activityIndicator, in the `ViewController.h`:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/AJ9yiLHCQ6C5yjXpBfGP_Xcode_s2_outlets.png\",\n        \"Xcode_s2_outlets.png\",\n        \"537\",\n        \"92\",\n        \"#a939ac\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\nNow, synthesize them in the `ViewController.m` :\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/9Yy0T1yRWuLogr9Z9vxK_Xcode_s2_synthesize.png\",\n        \"Xcode_s2_synthesize.png\",\n        \"204\",\n        \"41\",\n        \"#ae3284\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n\nAt this stage, the interface can be accessed by the MagicBeep class.\n\n## 10. Interacting with the interface\n\nAdd a method `addTextToView(NSString *str)` to the MagicBeep class. \nThis method adds a string to the textview :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"\\tvoid MagicBeep::addTextToView(NSString *str)\\n\\t{\\n\\t\\tviewController.mainText.text=[viewController.mainText.text stringByAppendingString:str] ;\\n\\t\\tNSLog(@\\\"%@\\\", str) ;\\n\\t}\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nNow use this function to notify the user about all events that are received.\nHere how to call the addTextToView method from the `processEvent` method: \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"\\tswitch (event.Type)\\n\\t\\t{\\n\\t\\t\\tcase EVT_STATUS :\\n\\t\\t\\t{\\n\\t\\t\\t\\tEventStatus &ev=event.Status ;\\n\\t\\t\\t\\tint bat=ev.getBattery() ;\\n\\t\\t\\t\\taddTextToView([NSString stringWithFormat:@\\\"Battery %d\\\\n\\\", bat]) ;\\n\\t\\t\\t}\\n\\t\\t\\tbreak ;\\n\\t\\t\\tcase EVT_PEN_2D :\\n\\t\\t\\t{\\n\\t\\t\\t\\tEventPen2D &ev=event.Pen2D ;\\n\\t\\t\\t\\tVector2D po=ev.getPosition() ;\\n\\t\\t\\t\\taddTextToView([NSString stringWithFormat:@\\\"EvtPen2D : %d : (%f , %f)\\\\n\\\", ev.Touch() ? 1 : 0, po.X, po.Y]) ;\\n\\n\\t\\t\\t}\\n\\t\\t\\tbreak ;\\n\\t\\t\\tcase EVT_HARDWARE :\\n\\t\\t\\t{\\n\\t\\t\\t\\tEventHardware &ev=event.HardwareEvent ;\\n\\t\\t\\t\\tswitch (ev.getHardwareEventType())\\n\\t\\t\\t\\t{\\n\\t\\t\\t\\tcase HE_BUTTON1_PRESSED :\\n\\t\\t\\t\\taddTextToView([NSString stringWithFormat:@\\\"Button 1 pressed\\\\n\\\"]) ;\\n\\t\\t\\t\\tbreak ;\\n\\t\\t\\t\\tcase HE_BUTTON2_PRESSED :\\n\\t\\t\\t\\taddTextToView([NSString stringWithFormat:@\\\"Button 2 pressed\\\\n\\\"]) ;\\n\\t\\t\\t\\tbreak ;\\n\\t\\t\\t\\tdefault :\\n\\t\\t\\t\\tbreak ;\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t\\tbreak ;\\n\\n\\t\\t\\tcase EVT_DESCRIPTION :\\n\\t\\t\\t{\\n\\t\\t\\t\\tEventDescription &ev=event.Description ;\\n\\t\\t\\t\\t// Convert std::wstring to NSString\\n\\t\\t\\t\\tNSString * sObjC = [[NSString alloc] initWithBytes:ev.getDeviceName().data()\\n\\t\\t\\t\\tlength:ev.getDeviceName().size() * sizeof(wchar_t)\\n\\t\\t\\t\\tencoding:NSUTF32LittleEndianStringEncoding];\\n\\t\\t\\t\\t[viewController.connectionStatus setTitle:[@\\\"Connected to slate \\\" stringByAppendingString: sObjC]];\\n\\n\\t\\t\\t\\taddTextToView([NSString stringWithFormat:@\\\"Slate Name : %@\\\\n\\\", sObjC]) ;\\n\\t\\t\\t}\\n\\t\\t\\tbreak ;\\n\\t\\t\\t\\n\\t\\t\\tcase EVT_SOFTWARE :\\n\\t\\t\\t{\\n\\t\\t\\t\\tEventSoftware &ev=event.SoftwareEvent ;\\n\\t\\t\\t\\tint p=ev.getObjectID() ;\\n\\t\\t\\t\\tswitch (ev.getSoftwareEventType())\\n\\t\\t\\t\\t{\\n\\t\\t\\t\\tcase SE_OBJECT_IN :\\n\\t\\t\\t\\t{\\n\\t\\t\\t\\taddTextToView([NSString stringWithFormat:@\\\"Object in %d\\\\n\\\", p]) ;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tbreak ;\\n\\t\\t\\t\\tcase SE_OBJECT_OUT :\\n\\t\\t\\t\\t{\\n\\t\\t\\t\\taddTextToView([NSString stringWithFormat:@\\\"Object out %d\\\\n\\\", p]) ;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t\\tbreak ;\\n\\n\\t\\t\\tdefault :\\n\\t\\t\\tbreak ;\\n\\t\\t}\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n## 11. Animate the activityIndicator\n\nTo indicate that the application is connecting to the Slate, we add the following line to the constructor of the MagicBeep class :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[viewController.activityIndicator startAnimating];\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nThe animation should be stopped and the indicator should disappear when the connection succeeds.\nAdd the following code to the `connectionStatusChanged` method, in the if(connected) scope :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"viewController.activityIndicator.hidesWhenStopped=true;\\n[viewController.activityIndicator stopAnimating];\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\n## 12. Play the Beep sound\n\nThis application plays a simple tone when a pen enters in the slate field of view.\nIn this example, three Wave files are added to the project :Beep.wav,Beep 2.wav and Beep 3.wav in new group called Sounds.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/9bWVHNXfTE68wEMcZESP_Xcode_s2_Sounds.png\",\n        \"Xcode_s2_Sounds.png\",\n        \"263\",\n        \"412\",\n        \"#1f53a1\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n\nAdd the definition of the sounds to the MagicBeep constructor :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"//Create first sound path\\nNSURL *soundURL1=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\\\"Beep\\\" ofType:@\\\"wav\\\"]];\\n// Create the first sound    \\nAudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL1, &beepTone1);\\n    \\n//Create second sound path   \\nNSURL *soundURL2=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\\\"Beep 2\\\" ofType:@\\\"wav\\\"]];  \\n// Create the second sound   \\nAudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL2, &beepTone2);\\n \\n//Create third sound path    \\nNSURL *soundURL3=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\\\"Beep 3\\\" ofType:@\\\"wav\\\"]];   \\n// Create the third sound   \\nAudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL3, &beepTone3);\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\nAdd playSound(int soundID) method to the MagicBeep class which plays a different sound when pen is detected.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// playSound function\\n\\nvoid MagicBeep::playSound(int soundID)\\n{   \\n\\tswitch (soundID)  \\n\\t{\\n\\t \\tcase  2: \\n\\t\\t{   \\n\\t\\t\\tAudioServicesPlaySystemSound(beepTone1);\\n\\t\\t}\\n\\t\\t\\tbreak ;\\n\\t\\tcase  3:\\n\\t\\t{   \\n\\t\\t\\tAudioServicesPlaySystemSound(beepTone2);\\n\\t\\t}\\n            break ;\\n     \\n\\t\\tcase  4:\\n\\t\\t{  \\n\\t\\t\\tAudioServicesPlaySystemSound(beepTone3);\\n\\t\\t}   \\n\\t\\t\\tbreak ;\\n\\t}\\n}\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nNow the sound is ready to be played.\nYou can play the sound when the pen is in the Slate field of view by using the playSound method :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"case EVT_SOFTWARE :     \\n{          \\n\\tEventSoftware &ev=event.SoftwareEvent ;\\n\\tint p=ev.getObjectID() ;\\n            \\n\\tswitch (ev.getSoftwareEventType())         \\n\\t{         \\n\\t\\tcase SE_OBJECT_IN :       \\n\\t\\t{          \\n\\t\\t\\taddTextToView([NSString stringWithFormat:@\\\"Object in %d\\\\n\\\", p]) ;        \\n\\t\\t\\tplaySound(p);      \\n\\t\\t}          \\n\\t\\t\\tbreak ;      \\n\\t\\tcase SE_OBJECT_OUT :       \\n\\t\\t{         \\n\\t\\t\\taddTextToView([NSString stringWithFormat:@\\\"Object out %d\\\\n\\\", p]) ;     \\n\\t\\t}\\n\\t\\t\\tbreak;          \\n\\t}      \\n}       \\n\\tbreak ;\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nTo sum up your MagicBeep.h and your MagicBeep.mm files should be like this:\n\nMagicBeep.h file :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#ifndef __MagicBeep__MagicBeep__\\n#define __MagicBeep__MagicBeep__\\n\\n#include <ISKN_API.h>\\n#import <AudioToolbox/AudioToolbox.h>\\n#import \\\"ViewController.h\\\"\\n\\nusing namespace ISKN_API;\\n\\n// Listener class\\nclass MagicBeep :public Listener\\n{  \\npublic:\\n    // ISKN API attributes\\n    SlateManager   *iskn_SlateManager;\\n  \\n    // Application specific attributes\\n    SystemSoundID beepTone1,beepTone2,beepTone3;\\n    ViewController *viewController;\\n    \\n    // Constructor\\n    MagicBeep(ViewController *viewController);\\n    \\n    // Inherited attributes\\n    void connectionStatusChanged(bool connected);\\n    void processEvent(ISKN_API::Event &event, unsigned int timecode);\\n    \\n    // Application specific methods\\n    void addTextToView(NSString *str);\\n    void playSound(int soundID);\\n    NSString* WString2NSString(const std::wstring& ws);\\n};\\n#endif /* defined(__MagicBeep__MagicBeep__) */\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n\nMagicBeep.mm file :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#include \\\"MagicBeep.h\\\"\\n\\nMagicBeep * magicBeep ;\\n\\n\\n// Cpp/Objective-C Wrapper function\\n\\nextern \\\"C\\\"\\nvoid launchMagicBeep(ViewController *viewController)\\n{\\n    try\\n    {\\n        magicBeep=new MagicBeep(viewController);\\n    }\\n    catch (Error &err)\\n    {\\n        NSLog(@\\\"Error\\\");\\n    }\\n}\\n\\n//MagicBeep constructor\\nMagicBeep::MagicBeep(ViewController *viewController)\\n{\\n    // Create slate manager\\n    iskn_SlateManager  = new SlateManager();\\n    \\n    //Register the MagicBeep class as a Listener\\n    iskn_SlateManager->registerListener(this) ;\\n    \\n    //Send the connect command\\n    NSLog(@\\\"Attempting to connect to ISKN Slate...\\\");\\n    addTextToView(@\\\"Attempting to connect to ISKN Slate...\\\");\\n    iskn_SlateManager->connect() ;\\n    \\n    // Get a pointer to the ViewController\\n    this->viewController=viewController;\\n    [viewController.activityIndicator startAnimating];\\n    \\n    //Create first sound path\\n    NSURL *soundURL1=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\\\"Beep\\\" ofType:@\\\"wav\\\"]];\\n    // Create the first sound\\n    AudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL1, &beepTone1);\\n    \\n    \\n    //Create second sound path\\n    NSURL *soundURL2=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\\\"Beep 2\\\" ofType:@\\\"wav\\\"]];\\n    // Create the second sound\\n    AudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL2, &beepTone2);\\n    \\n    \\n    //Create third sound path\\n    NSURL *soundURL3=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\\\"Beep 3\\\" ofType:@\\\"wav\\\"]];\\n    // Create the third sound\\n    AudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL3, &beepTone3);\\n    \\n}\\n\\n// connectionStatusChanged function \\nvoid MagicBeep::connectionStatusChanged(bool connected)\\n{\\n    if(connected){\\n        // Request Slate description\\n        iskn_SlateManager.request(REQ_DESCRIPTION);\\n        \\n        // Subscribe to events (Status, Software events, Hardware events and Pen 2D event)\\n        \\n        iskn_SlateManager.subscribe(\\n                                 AUTO_STATUS |\\n                                 AUTO_SOFTWARE_EVENTS |\\n                                 AUTO_HARDWARE_EVENTS |\\n                                 AUTO_PEN_2D\\n                                 ) ;\\n        \\n        viewController.activityIndicator.hidesWhenStopped=true;\\n        [viewController.activityIndicator stopAnimating];\\n        \\n        addTextToView(@\\\"[Connected]\\\\n\\\");\\n        NSLog(@\\\"[Connected]\\\\n\\\");\\n    }\\n    else\\n    {\\n        addTextToView(@\\\"[Could not connect]\\\\n\\\");\\n        NSLog(@\\\"[Could not connect]\\\\n\\\");\\n    }\\n}\\n\\n// processEvent function\\nvoid MagicBeep::processEvent(Event &event, unsigned int timecode)\\n{\\n    switch (event.Type)\\n    {\\n        case EVT_STATUS :\\n        {\\n            EventStatus &ev=event.Status ;\\n            int bat=ev.getBattery() ;\\n            addTextToView([NSString stringWithFormat:@\\\"Battery %d\\\\n\\\", bat]) ;\\n        }\\n            break ;\\n            \\n        case EVT_PEN_2D :\\n        {\\n            EventPen2D &ev=event.Pen2D ;\\n            Vector2D po=ev.getPosition() ;\\n            addTextToView([NSString stringWithFormat:@\\\"EvtPen2D : %d : (%f , %f)\\\\n\\\", ev.Touch() ? 1 : 0, po.X, po.Y]) ;\\n\\n        }\\n            break ;\\n            \\n        case EVT_HARDWARE :\\n        {\\n            EventHardware &ev=event.HardwareEvent ;\\n            switch (ev.getHardwareEventType())\\n            {\\n                case HE_BUTTON1_PRESSED :\\n                    addTextToView([NSString stringWithFormat:@\\\"Button 1 pressed\\\\n\\\"]) ;\\n                    break ;\\n                case HE_BUTTON2_PRESSED :\\n                    addTextToView([NSString stringWithFormat:@\\\"Button 2 pressed\\\\n\\\"]) ;\\n                    break ;\\n                default :\\n                    break ;\\n            }\\n        }\\n            break ;\\n            \\n        case EVT_DESCRIPTION :\\n        {\\n            EventDescription &ev=event.Description ;\\n            NSString *nss_deviceID = WString2NSString(ev.getDeviceName());\\n            // Convert std::wstring to NSString\\n            [viewController.connectionStatus setTitle:[@\\\"Connected to slate \\\" stringByAppendingString: nss_deviceID]];\\n\\n            addTextToView([NSString stringWithFormat:@\\\"Slate name : %@\\\\n\\\", nss_deviceID]) ;\\n        }\\n            break ;\\n                       \\n        case EVT_SOFTWARE :\\n        {\\n            EventSoftware &ev=event.SoftwareEvent ;\\n            int p=ev.getObjectID() ;\\n            switch (ev.getSoftwareEventType())\\n            {\\n                case SE_OBJECT_IN :\\n                {\\n                    addTextToView([NSString stringWithFormat:@\\\"Object in %d\\\\n\\\", p]) ;\\n                    playSound(p);\\n                }\\n                    break ;\\n                case SE_OBJECT_OUT :\\n                {\\n                    addTextToView([NSString stringWithFormat:@\\\"Object out %d\\\\n\\\", p]) ;\\n                }\\n                    break;\\n                case SE_HANDSHAKE:\\n                    \\n                    break;\\n            }\\n        }\\n            break ;\\n            \\n        default :\\n            break ;\\n    }  \\n}\\n\\n// addTextToView function\\nvoid MagicBeep::addTextToView(NSString *str)\\n{\\n    viewController.mainText.text=[viewController.mainText.text stringByAppendingString:str] ;\\n    NSLog(@\\\"%@\\\", str) ;\\n}\\n\\n// playSound function\\nvoid MagicBeep::playSound(int soundID)\\n{\\n    switch (soundID)\\n    {\\n        case  2:\\n        {\\n           AudioServicesPlaySystemSound(beepTone1);\\n        }\\n            break ;\\n            \\n        case  3:\\n        {\\n            AudioServicesPlaySystemSound(beepTone2);\\n        }\\n            break ;\\n        case  4:\\n        {\\n            AudioServicesPlaySystemSound(beepTone3);\\n        }\\n            break ;           \\n    }\\n}\\n\\n//Convert to NSString function\\nNSString* MagicBeep::WString2NSString(const std::wstring& ws)\\n{\\n    NSString* result = [[NSString alloc] initWithBytes:ws.data() length:ws.size()*sizeof(wchar_t)  encoding:NSUTF32LittleEndianStringEncoding];\\n    return result;\\n}\\n\",\n      \"language\": \"cplusplus\"\n    }\n  ]\n}\n[/block]\n## 13. Run your project\n\nYour project is now ready to run.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/Q5fOtOeuSYCi5AaE7Deh_Xcode_runYourProject.PNG\",\n        \"Xcode_runYourProject.PNG\",\n        \"717\",\n        \"538\",\n        \"#539dfc\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"magicbeep-example-on-ios","type":"basic","title":"MagicBeep example on iOS"}

MagicBeep example on iOS


# MagicBeep # Welcome to _the second tutorial_ example ! This example presents the fundamental steps to master the ISKN API on Xcode for iOS. You will learn how to connect to the slate, how to receive the slate events, and how to handle those events and get their parameters. This is a simple sound player application using the ISKN Slate. The application detects the presence of a pen and plays a beep sound when the pen enters in the slate field of view. The beep sounds depends on the pen colour. Note that you can find __the full source code__ for this example in the ISKN_API examples folder. ## 1.Set Up Your Project Before you start, be sure you have your development environment set up. In this example you need to create a __Single View Application__. You can specify _MagicBeep_ as a project name. Link the ISKN API to your project. To do so you can see the first tutorial [here](getting-started-with-iskn-api-on-ios). In addition to the ISKN API,you need to add three iOS frameworks to the application : CoreBluetooth.framework, UIKit.framework and AudioToolbox.framework. The CoreBluetooth framework provides the resources your iOS apps need to communicate with devices that are equipped with Bluetooth low energy (BTLE) technology like the ISKN Slate. The UIKit framework (UIKit.framework) provides the crucial infrastructure needed to construct and manage iOS apps. The AudioToolbox framework provides interfaces for recording, playback, and stream parsing. [block:image] { "images": [ { "image": [ "https://files.readme.io/i5L3E0iNSJaRiH28J3Hi_Xcode_s2_Buildphases.png", "Xcode_s2_Buildphases.png", "880", "297", "#813817", "" ] } ] } [/block] + Select the MagicBeep folder and right click on it.Select __New folder__ : [block:image] { "images": [ { "image": [ "https://files.readme.io/ZLhCuGXwQE6CfSMi2E9c_Xcode_s2_newFile.png", "Xcode_s2_newFile.png", "300", "120", "#2e64ab", "" ] } ] } [/block] In the left pane, select iOS then choose C++ file and click __Next__ : [block:image] { "images": [ { "image": [ "https://files.readme.io/S0QZGFqrQ6OytwEhpWvI_Xcode_s2_Add_cpp_File.png", "Xcode_s2_Add_cpp_File.png", "733", "432", "#1a3e7e", "" ] } ] } [/block] Specify MagicBeep as a name and check __Also create a header file__ option then click __Next__ : @image html Xcode_s2_cppFile_options.png @image rtf Xcode_s2_cppFile_options.png @image latex Xcode_s2_cppFile_options.png @image docbook Xcode_s2_cppFile_options.png [block:image] { "images": [ { "image": [ "https://files.readme.io/8mjCGEBlR7GgxHcpA4a9_Xcode_s2_cppFile_options.png", "Xcode_s2_cppFile_options.png", "736", "432", "#3268ad", "" ] } ] } [/block] Select __Create__ on the next Window. Xcode generates a header file 'MagicBeep.h' and a source file 'MagicBeep.cpp' under the MagicBeep folder. Now your Project navigator should look like this : [block:image] { "images": [ { "image": [ "https://files.readme.io/l3i9qenT3uzVKowh11Q6_Xcode_s2_projectNavigator.png", "Xcode_s2_projectNavigator.png", "262", "372", "#2057a5", "" ] } ] } [/block] Double click on the MagicBeep.cpp file and change the extension from cpp to mm. [block:image] { "images": [ { "image": [ "https://files.readme.io/4Y7wUMuSBirScLPQUrA2_Xcode_s2_projectNavigator2.png", "Xcode_s2_projectNavigator2.png", "262", "372", "#1c53a1", "" ] } ] } [/block] Since the ISKN API is a C++ library you need to mix C++ and Objective-C in the MagicBeep Files. By renaming the MagicBeep.cpp file to have a .mm extension you tell the compiler that this file combine the Objective-C and the C++ languages. ## 2.Including the ISKN API main header file Add a Header Search Path for the ISKN API header. To do so you can see the first tutorial [here](md_src_example_ios_s1.html). Include ISKN_API.h file in of the MagicBeep.h file : [block:code] { "codes": [ { "code": "#include \"ISKN_API.h\"", "language": "cplusplus" } ] } [/block] Since the MagicBeep class should interact with both the graphical interface and the Audio service. We need to import the `AudioToolbox.h` file as well as the `ViewController.h` file : [block:code] { "codes": [ { "code": "#import <AudioToolbox/AudioToolbox.h>\n#import \"ViewController.h\"", "language": "cplusplus" } ] } [/block] Create a C++ class with MagicBeep as name in the MagicBeep.h. Then add a reference to the ViewController class. This reference is used to interact with the graphical interface : [block:code] { "codes": [ { "code": "class MagicBeep \n{\n \npublic:\n MagicBeep(ViewController *viewController);\n \n ViewController *viewController;\n};", "language": "cplusplus" } ] } [/block] In the MagicBeep.mm, add MagicBeep constructor implementation. The constructor takes as a parameter a pointer to a ViewController. It saves this reference in the internal attribute viewController : [block:code] { "codes": [ { "code": "MagicBeep::MagicBeep(ViewController *viewController)\n{\n // Get a pointer to the view controller\n this->viewController=viewController; \n}", "language": "cplusplus" } ] } [/block] The viewController pointer allows access to the project ViewController. ## 3.Preparing the event listener class To receive the Slate events, you need to register a listener. In this example, the MagicBeep class extends the Listener class. [block:code] { "codes": [ { "code": "class MagicBeep : public Listener", "language": "cplusplus" } ] } [/block] The listener class is an interface providing the following methods : [block:code] { "codes": [ { "code": "void processEvent(ISKN_API::Event &e, unsigned int timecode);\nvoid connectionStatusChanged(bool connected);", "language": "cplusplus" } ] } [/block] Those methods __should be implemented__ by the subclass in order to receive the slate events. At this point, the MagicBeep listener class is ready to be registered. ## 4.Preparing the communication tools Before registering the listener, we need to create the Slate manager object. To do so, add those attributes to your MagicBeep class declaration : [block:code] { "codes": [ { "code": "// ISKN API attributes\n SlateManager *iskn_SlateManager;", "language": "cplusplus" } ] } [/block] In the constructor method of the MagicBeep class, create the slate manager object : [block:code] { "codes": [ { "code": " // Create slate manager\n iskn_SlateManager = new SlateManager();", "language": "cplusplus" } ] } [/block] ## 5. Registering the events listener Once the slate manager, is created, it is possible to register the MagicBeep class as a listener. To do so, use the registerListener method of the slate manager in MagicBeep constructor : [block:code] { "codes": [ { "code": "//Register the MagicBeep class as a Listener\n \tiskn_SlateManager->registerListener(this) ;", "language": "cplusplus" } ] } [/block] ## 6. Connect to the slate and subscribe to the services Before being able to receive slate events, the application should connect to the Slate. Use the `connect()` method of the Slate manager object to create a connection in the MagicBeep constructor : [block:code] { "codes": [ { "code": " //Send the connect command\n iskn_SlateManager->connect() ;", "language": "cplusplus" } ] } [/block] Check if the connection succeeded by implementing the `connectionStatusChanged(bool)` method : [block:code] { "codes": [ { "code": "// Connection status has changed\nvoid MagicBeep::connectionStatusChanged(bool connected)\n{\n if(connected){\n // Request Slate description\n iskn_SlateManager.request(REQ_DESCRIPTION);\n \n // Subscribe to events (Status, Pen Status, Function Call and Pen_3D)\n \n iskn_SlateManager.subscribe(\n AUTO_STATUS |\n AUTO_SOFTWARE_EVENTS |\n AUTO_HARDWARE_EVENTS |\n AUTO_PEN_3D\n ) ;\n \n addTextToView(@\"[Connected]\\n\");\n NSLog(@\"[Connected]\\n\");\n }\n else\n {\n addTextToView(@\"[Could not connect]\\n\");\n NSLog(@\"[Could not connect]\\n\");\n }\n}", "language": "cplusplus" } ] } [/block] Once connected, request the slate description in order to update the Device object information. This gathers specific slate information such as slate name, the size of the slate, the writing zone of the slate. This is performed by the request method of the Slate manager object. Finally, you need to subscribe to automatic events services. This tells the Slate which events your listener should receive. In this application, we request four types of events : + AUTO_STATUS : Asks to receive slate status changes (Battery charge change, (SD card insertion/ removal)). + AUTO_SOFTWARE_EVENTS : Asks to receive Software events like object status change. (Object recognised (SE_OBJECT_IN), object lost(SE_OBJECT_OUT), handshake event (a periodic event used to detect that the Slate is still on)). + AUTO_HARDWARE_EVENTS : Asks to receive Hardware events (When a button is pressed (new page button, new layer button, reset event (long press on new page button)), SD card inserted or removed ) + AUTO_PEN_2D : Asks to receive the Pen tip 2D position and contact status at a 140Hz frequency when the pen is in the field of view of the slate. ## 7. Receive and extract events The processEvent method is called whenever a new event is received from the Slate. Use the type attribute of the Event object in order to figure out the event type. You can use a switch case statement as follow : [block:code] { "codes": [ { "code": "switch (event.Type)\n {\n case EVT_STATUS :\n {\n //Slate status change detected\n }\n break ;\n \n case EVT_PEN_2D :\n {\n // New pen position and contact status\n }\n break ;\n \n case EVT_HARDWARE :\n {\n \t\t\t//A hardware event happened \n \t\t\tEventHardware &ev=event.HardwareEvent ;\n switch (ev.getHardwareEventType())\n {\n case HE_BUTTON1_PRESSED :\n Button 1 is pressed\n break ;\n case HE_BUTTON2_PRESSED :\n \t Button 2 is pressed\n break ;\n default :\n break ;\n }\n }\n break ;\n \n case EVT_DESCRIPTION :\n {\n \tEvent received after description request\n }\n break ;\n \n \n case EVT_SOFTWARE :\n {\n \t//A software event has happened\n \t\n EventSoftware &ev=event.SoftwareEvent ;\n \n switch (ev.getSoftwareEventType())\n {\n case SE_OBJECT_IN :\n {\n // A new object is detected\n }\n break ;\n case SE_OBJECT_OUT :\n {\n // Object lost\n }\n }\n }\n break ;\n \n default :\n \n break ;\n }", "language": "cplusplus" } ] } [/block] ## 8. Add a C wrapper to connect the objective-C and the C++ In order to link the view controller (Objective-C) to the MagicBeep class (C++), we use C function Wrappers. The first function `launchMagicBeep(ViewController *viewController)` is used to construct an instance of the MagicBeep class. The instance is declared in the MagicBeep.mm source file: [block:code] { "codes": [ { "code": "MagicBeep * magicBeep ;", "language": "cplusplus" } ] } [/block] The wrapper function is preceded by the `extern "C"` statement in order to specify that it is a C function. [block:code] { "codes": [ { "code": "extern \"C\"\nvoid launchMagicBeep(ViewController *viewController)\n{\ntry\n{\nmagicBeep=new MagicBeep(viewController);\n}\ncatch (Error &err)\n{\nNSLog(@\"Error\");\n}\n}", "language": "cplusplus" } ] } [/block] The wrapper function is called when the view is loaded. First in the `ViewController.m` file, add a prototype definition for the `launchMagicBeep` function. [block:code] { "codes": [ { "code": "extern void launchMagicBeep(ViewController* viewController) ;", "language": "cplusplus" } ] } [/block] Then call `launchMagicBeep` in the viewDidLoad method of your ViewController : [block:code] { "codes": [ { "code": "launchMagicBeep(self) ;", "language": "cplusplus" } ] } [/block] Now, the MagicBeep class has direct access to any synthesized property of the viewController. ## 9. Preparing the Storyboard In this application we use a simple interface with a `TextView`, a `Toolbar` with a single text item and an activity indicator to tell when the application is connecting to the Slate. [block:image] { "images": [ { "image": [ "https://files.readme.io/r0RqdhU5QXuXT7UWjIWS_Xcode_s2_preparing_storyboard.png", "Xcode_s2_preparing_storyboard.png", "791", "682", "#224c8e", "" ] } ] } [/block] Create outlets for the TextView, the item and the activityIndicator, in the `ViewController.h`: [block:image] { "images": [ { "image": [ "https://files.readme.io/AJ9yiLHCQ6C5yjXpBfGP_Xcode_s2_outlets.png", "Xcode_s2_outlets.png", "537", "92", "#a939ac", "" ] } ] } [/block] Now, synthesize them in the `ViewController.m` : [block:image] { "images": [ { "image": [ "https://files.readme.io/9Yy0T1yRWuLogr9Z9vxK_Xcode_s2_synthesize.png", "Xcode_s2_synthesize.png", "204", "41", "#ae3284", "" ] } ] } [/block] At this stage, the interface can be accessed by the MagicBeep class. ## 10. Interacting with the interface Add a method `addTextToView(NSString *str)` to the MagicBeep class. This method adds a string to the textview : [block:code] { "codes": [ { "code": "\tvoid MagicBeep::addTextToView(NSString *str)\n\t{\n\t\tviewController.mainText.text=[viewController.mainText.text stringByAppendingString:str] ;\n\t\tNSLog(@\"%@\", str) ;\n\t}", "language": "cplusplus" } ] } [/block] Now use this function to notify the user about all events that are received. Here how to call the addTextToView method from the `processEvent` method: [block:code] { "codes": [ { "code": "\tswitch (event.Type)\n\t\t{\n\t\t\tcase EVT_STATUS :\n\t\t\t{\n\t\t\t\tEventStatus &ev=event.Status ;\n\t\t\t\tint bat=ev.getBattery() ;\n\t\t\t\taddTextToView([NSString stringWithFormat:@\"Battery %d\\n\", bat]) ;\n\t\t\t}\n\t\t\tbreak ;\n\t\t\tcase EVT_PEN_2D :\n\t\t\t{\n\t\t\t\tEventPen2D &ev=event.Pen2D ;\n\t\t\t\tVector2D po=ev.getPosition() ;\n\t\t\t\taddTextToView([NSString stringWithFormat:@\"EvtPen2D : %d : (%f , %f)\\n\", ev.Touch() ? 1 : 0, po.X, po.Y]) ;\n\n\t\t\t}\n\t\t\tbreak ;\n\t\t\tcase EVT_HARDWARE :\n\t\t\t{\n\t\t\t\tEventHardware &ev=event.HardwareEvent ;\n\t\t\t\tswitch (ev.getHardwareEventType())\n\t\t\t\t{\n\t\t\t\tcase HE_BUTTON1_PRESSED :\n\t\t\t\taddTextToView([NSString stringWithFormat:@\"Button 1 pressed\\n\"]) ;\n\t\t\t\tbreak ;\n\t\t\t\tcase HE_BUTTON2_PRESSED :\n\t\t\t\taddTextToView([NSString stringWithFormat:@\"Button 2 pressed\\n\"]) ;\n\t\t\t\tbreak ;\n\t\t\t\tdefault :\n\t\t\t\tbreak ;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak ;\n\n\t\t\tcase EVT_DESCRIPTION :\n\t\t\t{\n\t\t\t\tEventDescription &ev=event.Description ;\n\t\t\t\t// Convert std::wstring to NSString\n\t\t\t\tNSString * sObjC = [[NSString alloc] initWithBytes:ev.getDeviceName().data()\n\t\t\t\tlength:ev.getDeviceName().size() * sizeof(wchar_t)\n\t\t\t\tencoding:NSUTF32LittleEndianStringEncoding];\n\t\t\t\t[viewController.connectionStatus setTitle:[@\"Connected to slate \" stringByAppendingString: sObjC]];\n\n\t\t\t\taddTextToView([NSString stringWithFormat:@\"Slate Name : %@\\n\", sObjC]) ;\n\t\t\t}\n\t\t\tbreak ;\n\t\t\t\n\t\t\tcase EVT_SOFTWARE :\n\t\t\t{\n\t\t\t\tEventSoftware &ev=event.SoftwareEvent ;\n\t\t\t\tint p=ev.getObjectID() ;\n\t\t\t\tswitch (ev.getSoftwareEventType())\n\t\t\t\t{\n\t\t\t\tcase SE_OBJECT_IN :\n\t\t\t\t{\n\t\t\t\taddTextToView([NSString stringWithFormat:@\"Object in %d\\n\", p]) ;\n\t\t\t\t}\n\t\t\t\tbreak ;\n\t\t\t\tcase SE_OBJECT_OUT :\n\t\t\t\t{\n\t\t\t\taddTextToView([NSString stringWithFormat:@\"Object out %d\\n\", p]) ;\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak ;\n\n\t\t\tdefault :\n\t\t\tbreak ;\n\t\t}", "language": "cplusplus" } ] } [/block] ## 11. Animate the activityIndicator To indicate that the application is connecting to the Slate, we add the following line to the constructor of the MagicBeep class : [block:code] { "codes": [ { "code": "[viewController.activityIndicator startAnimating];", "language": "cplusplus" } ] } [/block] The animation should be stopped and the indicator should disappear when the connection succeeds. Add the following code to the `connectionStatusChanged` method, in the if(connected) scope : [block:code] { "codes": [ { "code": "viewController.activityIndicator.hidesWhenStopped=true;\n[viewController.activityIndicator stopAnimating];", "language": "cplusplus" } ] } [/block] ## 12. Play the Beep sound This application plays a simple tone when a pen enters in the slate field of view. In this example, three Wave files are added to the project :Beep.wav,Beep 2.wav and Beep 3.wav in new group called Sounds. [block:image] { "images": [ { "image": [ "https://files.readme.io/9bWVHNXfTE68wEMcZESP_Xcode_s2_Sounds.png", "Xcode_s2_Sounds.png", "263", "412", "#1f53a1", "" ] } ] } [/block] Add the definition of the sounds to the MagicBeep constructor : [block:code] { "codes": [ { "code": "//Create first sound path\nNSURL *soundURL1=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\"Beep\" ofType:@\"wav\"]];\n// Create the first sound \nAudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL1, &beepTone1);\n \n//Create second sound path \nNSURL *soundURL2=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\"Beep 2\" ofType:@\"wav\"]]; \n// Create the second sound \nAudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL2, &beepTone2);\n \n//Create third sound path \nNSURL *soundURL3=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\"Beep 3\" ofType:@\"wav\"]]; \n// Create the third sound \nAudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL3, &beepTone3);", "language": "cplusplus" } ] } [/block] Add playSound(int soundID) method to the MagicBeep class which plays a different sound when pen is detected. [block:code] { "codes": [ { "code": "// playSound function\n\nvoid MagicBeep::playSound(int soundID)\n{ \n\tswitch (soundID) \n\t{\n\t \tcase 2: \n\t\t{ \n\t\t\tAudioServicesPlaySystemSound(beepTone1);\n\t\t}\n\t\t\tbreak ;\n\t\tcase 3:\n\t\t{ \n\t\t\tAudioServicesPlaySystemSound(beepTone2);\n\t\t}\n break ;\n \n\t\tcase 4:\n\t\t{ \n\t\t\tAudioServicesPlaySystemSound(beepTone3);\n\t\t} \n\t\t\tbreak ;\n\t}\n}", "language": "cplusplus" } ] } [/block] Now the sound is ready to be played. You can play the sound when the pen is in the Slate field of view by using the playSound method : [block:code] { "codes": [ { "code": "case EVT_SOFTWARE : \n{ \n\tEventSoftware &ev=event.SoftwareEvent ;\n\tint p=ev.getObjectID() ;\n \n\tswitch (ev.getSoftwareEventType()) \n\t{ \n\t\tcase SE_OBJECT_IN : \n\t\t{ \n\t\t\taddTextToView([NSString stringWithFormat:@\"Object in %d\\n\", p]) ; \n\t\t\tplaySound(p); \n\t\t} \n\t\t\tbreak ; \n\t\tcase SE_OBJECT_OUT : \n\t\t{ \n\t\t\taddTextToView([NSString stringWithFormat:@\"Object out %d\\n\", p]) ; \n\t\t}\n\t\t\tbreak; \n\t} \n} \n\tbreak ;", "language": "cplusplus" } ] } [/block] To sum up your MagicBeep.h and your MagicBeep.mm files should be like this: MagicBeep.h file : [block:code] { "codes": [ { "code": "#ifndef __MagicBeep__MagicBeep__\n#define __MagicBeep__MagicBeep__\n\n#include <ISKN_API.h>\n#import <AudioToolbox/AudioToolbox.h>\n#import \"ViewController.h\"\n\nusing namespace ISKN_API;\n\n// Listener class\nclass MagicBeep :public Listener\n{ \npublic:\n // ISKN API attributes\n SlateManager *iskn_SlateManager;\n \n // Application specific attributes\n SystemSoundID beepTone1,beepTone2,beepTone3;\n ViewController *viewController;\n \n // Constructor\n MagicBeep(ViewController *viewController);\n \n // Inherited attributes\n void connectionStatusChanged(bool connected);\n void processEvent(ISKN_API::Event &event, unsigned int timecode);\n \n // Application specific methods\n void addTextToView(NSString *str);\n void playSound(int soundID);\n NSString* WString2NSString(const std::wstring& ws);\n};\n#endif /* defined(__MagicBeep__MagicBeep__) */", "language": "cplusplus" } ] } [/block] MagicBeep.mm file : [block:code] { "codes": [ { "code": "#include \"MagicBeep.h\"\n\nMagicBeep * magicBeep ;\n\n\n// Cpp/Objective-C Wrapper function\n\nextern \"C\"\nvoid launchMagicBeep(ViewController *viewController)\n{\n try\n {\n magicBeep=new MagicBeep(viewController);\n }\n catch (Error &err)\n {\n NSLog(@\"Error\");\n }\n}\n\n//MagicBeep constructor\nMagicBeep::MagicBeep(ViewController *viewController)\n{\n // Create slate manager\n iskn_SlateManager = new SlateManager();\n \n //Register the MagicBeep class as a Listener\n iskn_SlateManager->registerListener(this) ;\n \n //Send the connect command\n NSLog(@\"Attempting to connect to ISKN Slate...\");\n addTextToView(@\"Attempting to connect to ISKN Slate...\");\n iskn_SlateManager->connect() ;\n \n // Get a pointer to the ViewController\n this->viewController=viewController;\n [viewController.activityIndicator startAnimating];\n \n //Create first sound path\n NSURL *soundURL1=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\"Beep\" ofType:@\"wav\"]];\n // Create the first sound\n AudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL1, &beepTone1);\n \n \n //Create second sound path\n NSURL *soundURL2=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\"Beep 2\" ofType:@\"wav\"]];\n // Create the second sound\n AudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL2, &beepTone2);\n \n \n //Create third sound path\n NSURL *soundURL3=[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\"Beep 3\" ofType:@\"wav\"]];\n // Create the third sound\n AudioServicesCreateSystemSoundID((__bridge CFURLRef) soundURL3, &beepTone3);\n \n}\n\n// connectionStatusChanged function \nvoid MagicBeep::connectionStatusChanged(bool connected)\n{\n if(connected){\n // Request Slate description\n iskn_SlateManager.request(REQ_DESCRIPTION);\n \n // Subscribe to events (Status, Software events, Hardware events and Pen 2D event)\n \n iskn_SlateManager.subscribe(\n AUTO_STATUS |\n AUTO_SOFTWARE_EVENTS |\n AUTO_HARDWARE_EVENTS |\n AUTO_PEN_2D\n ) ;\n \n viewController.activityIndicator.hidesWhenStopped=true;\n [viewController.activityIndicator stopAnimating];\n \n addTextToView(@\"[Connected]\\n\");\n NSLog(@\"[Connected]\\n\");\n }\n else\n {\n addTextToView(@\"[Could not connect]\\n\");\n NSLog(@\"[Could not connect]\\n\");\n }\n}\n\n// processEvent function\nvoid MagicBeep::processEvent(Event &event, unsigned int timecode)\n{\n switch (event.Type)\n {\n case EVT_STATUS :\n {\n EventStatus &ev=event.Status ;\n int bat=ev.getBattery() ;\n addTextToView([NSString stringWithFormat:@\"Battery %d\\n\", bat]) ;\n }\n break ;\n \n case EVT_PEN_2D :\n {\n EventPen2D &ev=event.Pen2D ;\n Vector2D po=ev.getPosition() ;\n addTextToView([NSString stringWithFormat:@\"EvtPen2D : %d : (%f , %f)\\n\", ev.Touch() ? 1 : 0, po.X, po.Y]) ;\n\n }\n break ;\n \n case EVT_HARDWARE :\n {\n EventHardware &ev=event.HardwareEvent ;\n switch (ev.getHardwareEventType())\n {\n case HE_BUTTON1_PRESSED :\n addTextToView([NSString stringWithFormat:@\"Button 1 pressed\\n\"]) ;\n break ;\n case HE_BUTTON2_PRESSED :\n addTextToView([NSString stringWithFormat:@\"Button 2 pressed\\n\"]) ;\n break ;\n default :\n break ;\n }\n }\n break ;\n \n case EVT_DESCRIPTION :\n {\n EventDescription &ev=event.Description ;\n NSString *nss_deviceID = WString2NSString(ev.getDeviceName());\n // Convert std::wstring to NSString\n [viewController.connectionStatus setTitle:[@\"Connected to slate \" stringByAppendingString: nss_deviceID]];\n\n addTextToView([NSString stringWithFormat:@\"Slate name : %@\\n\", nss_deviceID]) ;\n }\n break ;\n \n case EVT_SOFTWARE :\n {\n EventSoftware &ev=event.SoftwareEvent ;\n int p=ev.getObjectID() ;\n switch (ev.getSoftwareEventType())\n {\n case SE_OBJECT_IN :\n {\n addTextToView([NSString stringWithFormat:@\"Object in %d\\n\", p]) ;\n playSound(p);\n }\n break ;\n case SE_OBJECT_OUT :\n {\n addTextToView([NSString stringWithFormat:@\"Object out %d\\n\", p]) ;\n }\n break;\n case SE_HANDSHAKE:\n \n break;\n }\n }\n break ;\n \n default :\n break ;\n } \n}\n\n// addTextToView function\nvoid MagicBeep::addTextToView(NSString *str)\n{\n viewController.mainText.text=[viewController.mainText.text stringByAppendingString:str] ;\n NSLog(@\"%@\", str) ;\n}\n\n// playSound function\nvoid MagicBeep::playSound(int soundID)\n{\n switch (soundID)\n {\n case 2:\n {\n AudioServicesPlaySystemSound(beepTone1);\n }\n break ;\n \n case 3:\n {\n AudioServicesPlaySystemSound(beepTone2);\n }\n break ;\n case 4:\n {\n AudioServicesPlaySystemSound(beepTone3);\n }\n break ; \n }\n}\n\n//Convert to NSString function\nNSString* MagicBeep::WString2NSString(const std::wstring& ws)\n{\n NSString* result = [[NSString alloc] initWithBytes:ws.data() length:ws.size()*sizeof(wchar_t) encoding:NSUTF32LittleEndianStringEncoding];\n return result;\n}\n", "language": "cplusplus" } ] } [/block] ## 13. Run your project Your project is now ready to run. [block:image] { "images": [ { "image": [ "https://files.readme.io/Q5fOtOeuSYCi5AaE7Deh_Xcode_runYourProject.PNG", "Xcode_runYourProject.PNG", "717", "538", "#539dfc", "" ] } ] } [/block]