Tutorial   Class/Enum List   File List   Compound Members  

The Kontrol Dj "SDK" Tutorial

Introduction    Download    Getting Started    Error Handling    Probing Devices    Sending messages to KDj controller    Receiving messages from KDj controller    Compiling    Debugging    API Notes    License

Introduction

The KDJ500 Software Development Kit (SDK) is a programming package that allows software developers to quickly and easily write applications for the KDJ500 controller. The SDK is the tool that you use to communicate with the KDJ500 controller throught the usb port. The SDK includes and extensive documentation that explains how to use it, some example programs and a set of C++ base classes (KDjKernel and KDjExtended) which provide a common API (Application Programming Interface) for realtime input/output communication with KDj devices across Linux, Macintosh OS X, and Windows operating systems. This SDK significantly simplifies the process of interacting with the KDj controller. It was designed with the following goals:

KDjKernel is a base class for "low level" realtime input/output communication with KDj devices. KDjExtended is a base class for "high level" realtime input/output communication with KDj devices. Each class instance supports only a single KDj controller connection. KDj controller data is passed to the user as raw bytes using an std::vector<unsigned char> (messages in advance). The length of these messages is always 8 bytes.

Download

Latest Release (08 March 2005): Version 1.2.0

Getting Started

The first thing that must be done when using the KDj base classes is to derive your class from KDjKernel or KDjExtended classes. Each default constructor attempts to establish any necessary "connections" with the underlying system. KDjKernel and KDjExtended classes use C++ exceptions to report errors, necessitating try/catch blocks around many member functions. An KDjError can be thrown during instantiation in some circumstances. A warning message may also be reported if no KDj devices are found during instantiation. The KDjKernel and KDjExtended classes have been designed to work with "hot pluggable" KDj devices, making it possible to connect to KDj devices that may not have been present when the classes were instantiated. The following code example demonstrates default object construction and destruction:

#include "KontrolDj.h"

class myDerivedKDjClass : public KDjExtended{};

int main()
{
  myDerivedKDjClass *myKDj = 0;

  // myDerivedKDjClass constructor.
  try {
    myKDj = new myDerivedKDjClass();
  }
  catch (KDjError &error) {
    // Handle the exception here
    error.printMessage();
  }

  // Clean up.
  delete myKDj;
}

Obviously, this example doesn't demonstrate any of the real functionality of the KDjExtended class. However, all uses of the derived classes must begin with construction and must end with class destruction. Further, it is necessary that all class methods which can throw a C++ exception be called within a try/catch block.

Error Handling

KDj base classes use a C++ exception handler called KDjError, which is declared and defined in KontrolDj.h. The KDjError class is quite simple but it does allow errors to be "caught" by KDjError::Type. Many KDjKernel and KDjExtended methods can "throw" an KDjError, most typically if a driver error occurs or an invalid function argument is specified. There are a number of cases within base classes where warning messages may be displayed but an exception is not thrown. There is a protected base class method, error(), which can be modified to globally control how these messages are handled and reported. Messages associated with caught exceptions can be displayed with, for example, the KDjError::printMessage() function.

Probing Devices

A programmer may wish to query the available KDj controllers before deciding which to use. The following example outlines how this can be done. For a complete example, see the kdjinfo.cpp program in the tests directory.

// Probing Devices
// kdjinfo.cpp

#include <iostream>
#include "KontrolDj.h"

class myDerivedKDjClass : public KDjExtended{};

int main()
{
  myDerivedKDjClass *myKDj = 0;

  // myDerivedKDjClass constructor.
  try {
    myKDj = new myDerivedKDjClass();
  }
  catch (KDjError &error) {
    error.printMessage();
    exit(EXIT_FAILURE);
  }

  // Check devices.
  unsigned int nDevices = myKDj->getDeviceCount();
  std::cout << "\nThere are " << nDevices
            << " KDj devices available.\n";
  std::string deviceName;
  for ( unsigned int i=0; i<nDevices; i++ ) {
    try {
      deviceName = myKDj->getDeviceName(i);
    }
    catch (KDjError &error) {
      error.printMessage();
      goto cleanup;
    }
    std::cout << "  KDj device #" << i+1 << ": "
              << deviceName << '\n';
  }


  // Clean up.
 cleanup:
  delete myKDj;

  return 0;
}

Sending messages to KDj controller

The KDj controller uses an internal FIFO buffer to receive command messages. These messages are send by the user to the buffer via calls to the KDjKernel::sendMessage() function in the KDjKernel base class (low level) or with high level functions in the KDjExtended base class (i.e.: KDjExtended::setControllerMode()). In the following example, we omit necessary error checking and details regarding OS-dependent sleep functions. For a complete example, see the kdjout.cpp program in the tests directory.

// Sending messages to KDj controller
// kdjout.cpp

#include <iostream>
#include "KontrolDj.h"

class myDerivedKDjClass : public KDjExtended{};

int main()
{
  myDerivedKDjClass *myKDj = 0;
  myKDj = new myDerivedKDjClass();
  std::vector<unsigned char> message(8);

  // Check available devices.
  unsigned int nDevices = myKDj->getDeviceCount();
  if ( nDevices == 0 ) {
    std::cout << "No KDj devices available!\n";
    goto cleanup;
  }

  // Open first available device.
  myKDj->openDevice( 0 );

  // Send out a series of command messages.

  // Set the controller in slave mode (using high level function).
  myKDj->setControllerMode( 1 );
  SLEEP( 2000 ); // Platform-dependent.

  // Turn on all the leds.
  myKDj->setLedsStates( 0xFFFF );
  SLEEP( 2000 ); // Platform-dependent.

  // Turn off all the leds.
  myKDj->setLedsStates( 0x0000 );
  SLEEP( 2000 ); // Platform-dependent.

  // Turn on led_play_A (number 10).
  myKDj->setLedState( 10, 1 );
  SLEEP( 2000 ); // Platform-dependent.

  // Turn on led_cue_A (number 13).
  myKDj->setLedState( 13, 1 );
  SLEEP( 2000 ); // Platform-dependent.

  // Set the controller in master mode (using low level function).
  message.at(0) = KDJ_SET_CONTROLLER_MODE;
  message.at(1) = 0;
  myKDj->sendMessage( &message );

  // Clean up
 cleanup:
  delete myKDj;

  return 0;
}

Receiving messages from KDj controller

The KDj controller uses an internal FIFO buffer to send command messages. These messages are read from the buffer by the user via calls to the KDjKernel::getMessage() function in the KDjKernel base class (low level) or with the KDjExtended::doBufferProcessing() function in the KDjExtended base class (high level). We'll provide examples of both usages.

Receiving messages ( low level )

The KDjKernel::getMessage() is a blocking function, it does not return until a message has been read or when the read timeout timer expires. If a message is available in the FIFO buffer, it is copied to the user-provided std::vector<unsigned char> container. When no message is available, the function returns an empty container. The default read timeout is 0.5 seconds. This value may be modified in the KontrolDj.cpp source file. The maximum FIFO receive buffer size is 384 bytes (48 messages). If the maximum FIFO receive buffer size limit is reached, subsequent incoming messages are discarded until the FIFO buffer size is reduced.

In the following example, we omit some necessary error checking and details regarding OS-dependent functions. For a more complete example, see the lkdjin.cpp program in the tests directory.

// Receiving messages ( low level )
// lkdjin.cpp

#include <iostream>
#include <signal.h>
#include "KontrolDj.h"

class myDerivedKDjClass : public KDjKernel{};

bool done;
static void finish(int ignore){ done = true; }

int main()
{
  myDerivedKDjClass *myKDj = new myDerivedKDjClass();
  std::vector<unsigned char> message;
  int i;

  // Check available devices.
  unsigned int nDevices = myKDj->getDeviceCount();
  if ( nDevices == 0 ) {
    std::cout << "No KDj devices available!\n";
    goto cleanup;
  }
  myKDj->openDevice( 0 );

  // Install an interrupt handler function.
  done = false;
  (void) signal(SIGINT, finish);

  // Periodically check KDj FIFO buffer.
  std::cout << "Reading messages from buffer ... quit with Ctrl-C.\n";
  while ( !done ) {
    if( message.size() == 0 ) message.assign( 8, 0 );
    myKDj->getMessage( &message );
    if( !message.empty() ) {
      std::cout << "Received command message #: "
                << (int) message.at(0) << '\n';
    }
  }

  // Clean up
 cleanup:
  delete myKDj;

  return 0;
}

Receiving messages ( high level )

Each time KDjExtended::doBufferProcessing() function is called a message from the KDj controller FIFO buffer is read, the message is processed, if the message has an avaliable event "handler" method then it will be called. The KDjExtended base class provides several "handler" methods (onButtonPress, onPotentiometerChange... ), these do nothing in the base class, but a derived class can override them to implement any special processing that should occur as a result of their event actions.

By default, some messages are ignored in the KDjExtended::doBufferProcessing() process, but this function can be modified to control how these messages are handled.

In the following example, we omit some necessary error checking. For a more complete example, see the hkdjin.cpp program in the tests directory.

// Receiving messages ( high level )
// hkdjin.cpp

#include <iostream>
#include "KontrolDj.h"

class myDerivedKDjClass : public KDjExtended
{
  protected:
    void onButtonPress( unsigned char button, unsigned char flags,
                        std::vector<unsigned char> *midiMessage ){
      std::cout << "Button pressed number #: " << (int)button << '\n';
    };
};

bool done;
static void finish(int ignore){ done = true; }

int main()
{
  myDerivedKDjClass *myKDj = new myDerivedKDjClass();

  // Check available devices.
  unsigned int nDevices = myKDj->getDeviceCount();
  if ( nDevices == 0 ) {
    std::cout << "No KDj devices available!\n";
    goto cleanup;
  }
  myKDj->openDevice( 0 );

  // Install an interrupt handler function.
  done = false;
  (void) signal(SIGINT, finish);

  // Periodically check KDj FIFO buffer.
  std::cout << "Reading and processing messages from buffer
                ... quit with Ctrl-C.\n";
  while ( !done ) {
    myKDj->doBufferProcessing();
  }

  // Clean up
 cleanup:
  delete myKDj;

  return 0;
}

Compiling

In order to compile KDj base classes and their derived classes for a specific OS and API, it is necessary to supply the appropriate preprocessor definition and library within the compiler statement:

OS: Driver API: Preprocessor Definition: Library or Framework: Example Compiler Statement:
Linux __KDJ_LINUX_API__
Macintosh OS X IOKit __KDJ_MACOSX_API__ IOKit compiler specific
Windows FTD2XX __KDJ_WINDOWS_API__ FTD2XX.lib, FTD2XX.dll compiler specific

Debugging

If you are having problems getting KDj base classes and their derived classes to run on your system, try passing the preprocessor definition __KDJ_DEBUG__ to the compiler ( or uncomment the definition at the top of the file KontrolDj.cpp ). A variety of warning messages will be displayed which may help in determining the problem. Also try using the programs included in the test directory. The program kdjinfo displays all KDj devices found.

API Notes

KDj base classes are designed to provide a common API across the various supported operating systems and driver libraries. Despite that, some issues should be mentioned with regard to each.

Linux:

Coming soon.

Macintosh OS X:

The Apple IOKit API is used to do serial I/O with the Kontrol Dj controller.

Windows:

KDj base classes and test examples were originally developed with Borland compiler.

License

Kontrol Dj SDK: Kontrol Dj realtime i/o c++ classes
Copyright © 2005 by LSD Software. All Rights Reserved

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


Copyright © 2005 by LSD Software. All Rights Reserved.
Maintained by LSD, info at kontrol-dj.com