breakbeat

Breakbeat originated from the sampling of old funk and jazz records. The music breaks down to make room for the beat – and with the advent of sampling technology – provides a window of opportunity for capturing clean drum samples. The rhythmic structure of drumming lays the foundation for most musical genres. It’s no surprise then, that breakbeat samples have spawned several new genres of music, most notably: hip hop, jungle, and drum ‘n bass.

Jungle and drum ‘n bass are littered with two famous samples:

  • Amen
  • Funky Drummer

The Amen break is from the B-side of a single called ”Color me father” by a Soul/RnB group called The Winstons. The Funky Drummer break was originally played by Clyde Stubblefield from a James Brown record.

I implore anyone reading this, never to use these samples. I believe one of the precepts of a genre like drum ‘n bass is to explore new and interesting drum patterns; not to fatigue the user by recycling the same break with a myriad of slight alterations. The saturation point for these two breaks (and many others) was hit a long time ago. Reuse in this context, has limits.

Hello Kondo!

I’m sure the marketing department will tell you that the Kondo KHR-1 is a programmable humanoid robot capable of amazing feats.

It looks humanoid. It’s programmable – via the RCB-1 board mounted on its back. It’s certainly a robot. However, in its current state it’s nothing more than a bunch of servos held together by aluminum brackets. Only through programmability can we bring it to life.

Set aside your dreams of artificial intelligence for the moment. The first thing we need to accomplish is basic movement. The equivalent of a “Hello World!” app for the KHR-1 is the following:

Move the slider, move the head. Once you learn to move one servo, you can move many.

Communication between the PC and the RCB-1 happens through the serial port. If your computer (ie. laptop) doesn’t have a serial port, you can purchase a USB to serial port adapter.

Thankfully, the release of .NET 2.0 saw the introduction of a SerialPort class (found under the System.IO.Ports namespace). You can drag ‘n drop an instance of the SerialPort control from the Toolbox onto your Form. Here”s the Form constructor:


public Form1()
{
    InitializeComponent();
    this.serialPort1 = new System.IO.Ports.SerialPort();
    this.serialPort1.BaudRate = 115200;

    // change to whatever port # you're using
    this.serialPort1.PortName = "COM4";
    this.serialPort1.ReadTimeout = 30; // ms timeout

    try
    {
        serialPort1.Open();
    }
    catch(Exception e)
    {
        MessageBox.Show(e.Message + "nnBe sure to change the port # in code");
    }
}
 

If the serial port is successfully opened, trackbar events will be routed to the RotateHead method:


private void OnTrackbarScroll(object sender, EventArgs e)
{
    if (serialPort1.IsOpen)
        this.RotateHead((byte)this.trackBar1.Value);
}
 

To communicate with the RCB-1, fill an array of bytes and send them out the port. How do you know what bytes to send? A command reference PDF is available for download, however it’s not written in English. Fortunately, it has been translated. Here is page six from the RCB1stdraft.doc included with the download:

This page details the command used to send positional data to one or more servos. TX stands for transmission. An array of 16 bytes needs to be filled with the following information:

  • Byte 1 – The command. 0xFD to flag a servo position change.
  • Byte 2 – The board ID. The KHR-1 has two RCB-1 boards. One board controls servos 1-12, the other board controls servos 13-24.
  • Byte 3 – The servo speed. Eight speeds are supported with 0 being fastest and 7 the slowest.
  • Bytes 4-15 – The servo degree. There are 12 channels (corresponding to servos on either board) specifying the degree of rotation.
  • Byte 16 – A checksum. This is a value computed from the contents of the packet. The RCB-1 will calculate the checksum (given the contents) to determine if the data was sent correctly.

public void RotateHead(byte degree)
{
    byte[] by = new byte[16];
    byte command = 0xFD;
    byte boardId = 0;
    byte speed   = 0; // 0 = fastest, 7 = slowest

    by[0] = command;
    by[1] = boardId;
    by[2] = speed;

    // you can rotate the servos 0 to 180
    // so set unused channels to a value beyond this range
    by[3] = 255; // ch 1
    by[4] = 255; // ch 2
    by[5] = 255; // ch 3
    by[6] = 255; // ch 4
    by[7] = 255; // ch 5
    by[8] = degree; // ch 6 - the head on my kondo
    by[9]  = 255; // ch 7
    by[10] = 255; // ch 8
    by[11] = 255; // ch 9
    by[12] = 255; // ch 10
    by[13] = 255; // ch 11
    by[14] = 255; // ch 12
    by[15] = (byte)(command + boardId + speed + (255 * 11 + degree) & 0x7F);

    Trace.WriteLine("sending...");
    this.serialPort1.Write(by, 0, by.Length);
}
 

You can download the source here.

powermate

The Griffin PowerMate is a USB input device. In addition to the hardware, it comes with a driver and a control panel. The PowerMate control panel allows you to map a “User Action” to a “Computer Action”. For example, when the user rotates the knob right, the page in Internet Explorer will scroll down:

For the majority of end users, this is all the customization they need. However, wouldn’t it be nice if we could program directly against the PowerMate? That’s the focus of today’s post and here’s a screenshot of the resulting app:

The first requirement to programming the PowerMate is a copy of the Windows Driver Development Kit (DDK). The Windows Server 2003 SP1 DDK is free. However, you will have to pay for shipping and handling of the CD to your door. The option to download is available only to MSDN subscribers. After installation, the directory paths will need to be set. Add the DDK directory path to the start of the search path (bottom of the list) to avoid compilation errors.

The Solution distributed with this post has two projects:

  • C++/CLI class library for the PowerMate code
  • C# application to test the PowerMate.dll

Let’s begin by listing the types and data members of the PowerMate class. First, simple enums to represent button state and rotational direction:


public: enum class ButtonState
{
    Up,
    Down
};

public: enum class RotationalDirection
{
    Left,
    Right
};
 

Next, we have a private enum representing human interface device (HID) attributes for the PowerMate hardware. These values will be compared against HID attributes for each device returned during the enumeration process.


private: enum class HidAttributes
{
    VendorID      = 0x077d,
    ProductID     = 0x0410,
    VersionNumber = 0x0311
};
 

A kernel object handle to the HID. We’ll be using this handle for read/write operations later on.


private: HANDLE handleToDevice;
 

A managed thread handle. The thread created will be used for event notification and only terminates when the exit event is triggered.


private: Thread^ inputThread;
private: ManualResetEvent^ exitEvent
 

Next, we have storage for a rotational value that is clamped between the upper and lower bounds. By default, the bounds are between -100 and 100. If a user continues rotating the knob beyond the specified range the event will be ignored and the delegate will not fire. Of course, you’re free to alter this feature.


privateint rotationValue;
privateint rotationLowerBound;
privateint rotationUpperBound;
 

Finally, delegates for button and rotation events:


publicdelegate void RotationHandler(RotationalDirection direction, int value);
publicdelegate void ButtonHandler(ButtonState bs);
private: RotationHandler^ rotationDelegate;
private: ButtonHandler^ buttonDelegate;
 

Clients can subscribe to events using the following event accessors:


publicevent RotationHandler^ RotateEvent
{
    void add(RotationHandler^ value)
    {
        rotationDelegate += value;
    }

    void remove(RotationHandler^ value)
    {
        rotationDelegate -= value;
    }
}

publicevent ButtonHandler^ ButtonEvent
{
    void add(ButtonHandler^ value)
    {
        buttonDelegate += value;
    }

    void remove(ButtonHandler^ value)
    {
        buttonDelegate -= value;
    }
}
 

Before we examine more properties of the PowerMate class, let’s first have a look at its two-stage construction. The constructor is trivial so we can safely skip it. After construction, the Initialize method needs to be called. Initialize will enumerate available HID devices and open the first PowerMate device it encounters. Once you’ve successfully programmed one PowerMate device, you can easily modify the code to suport many – perhaps by creating a PowerMateManager class to maintain a list of every PowerMate connected to the system.

The Initialize method begins by finding and shutting down the PowerMate Control Panel. Why? The PowerMate Control Panel intercepts input and executes the appropriate action stored in its settings. An example of one such setting is ”Increase volume” under Global settings. As our app responds to the user performing a right rotation, the PowerMate Control Panel also responds to this action and increases the system volume. To obtain exclusive access to the hardware, we need to close the PowerMate Control Panel (PowerMate.exe).

Please note that all of the code related to the Initialize method has been stripped clean of of error handling and conditionals for presentation purposes.


array^ powerMateProcess = Process::GetProcessesByName("PowerMate");

HANDLE hp = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE,
                        FALSE,
                        powerMateProcess[0]->Id);

HWND hWnd = FindWindow(NULL, L"PowerMateWnd");
PostMessage(hWnd, WM_CLOSE, 0, 0);
WaitForSingleObject(hp, 5000);
 

Now it’s time to put that DDK to work. This section of the Initialize method involves the following steps:

  1. Get the HID GUID.
  2. Obtain a handle to a device information set.
  3. Enumerate device interfaces.
  4. Open a device.
  5. Check for matching HID attributes.

Step 1: Get the HID GUID.
This GUID represents a device interface that the driver exposes. Device interfaces with the same functionality are grouped together in interface classes. For example, all joysticks on the system could be members of the joystick device interface class.


GUID hidClass;
HidD_GetHidGuid(&hidClass);
 

Step 2: Obtain a handle to a device information set.
A device information set consists of device information elements. A device information element contains a list of all device interfaces associated with a particular device. The SetupDiGetClassDevs function retrieves a set of devices for the specified class. In other words, a list of HID-compliant devices.


HDEVINFO hDevInfoSet = SetupDiGetClassDevs(&hidClass,
                                           NULL,
                                           NULL,
                                           DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
 

Step 3: Enumerate device interfaces.
To communicate with the device, we need to open the device. To open the device, we need a device path. The device path is retrieved during the enumeration process and involves the following steps:

  • For each device class in the device information set, call SetupDiEnumDeviceInterfaces.
  • Each call to the above function returns an SP_DEVICE_INTERFACE_DATA structure.
  • We pass the above structure to SetupDiGetDeviceInterfaceDetail.
  • The above method returns an SP_DEVICE_INTERFACE_DETAIL_DATA structure.
  • The SP_DEVICE_INTERFACE_DETAIL_DATA structure contains the device path.

SP_INTERFACE_DEVICE_DATA interfaceData;
interfaceData.cbSize = sizeof(interfaceData);

for (int i = 0;
     SetupDiEnumDeviceInterfaces(hDevInfoSet,
                                 NULL,
                                 &hidClass,
                                 i,
                                 &interfaceData);
     ++i)
{
    // determine buffer size first
    DWORD bufferLength;
    SetupDiGetDeviceInterfaceDetail(hDevInfoSet,
                                    &interfaceData,
                                    NULL,
                                    0,
                                    &bufferLength,
                                    NULL);

    // then allocate
    PSP_INTERFACE_DEVICE_DETAIL_DATA interfaceDetail =
        (PSP_INTERFACE_DEVICE_DETAIL_DATA)new char[bufferLength];

    interfaceDetail->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);

    SetupDiGetDeviceInterfaceDetail(hDevInfoSet,
                                    &interfaceData,
                                    interfaceDetail,
                                    bufferLength,
                                    NULL,
                                    NULL);
 

Step 4: Open a device.
With a successful call to SetupDiGetDeviceInterfaceDetail above we now have a device path to pass into CreateFile. Upon success, the CreateFile function will open the device and return a handle to it.


HANDLE hDevice = CreateFile(interfaceDetail->DevicePath,
                            GENERIC_READ | GENERIC_WRITE,
                            FILE_SHARE_READ | FILE_SHARE_WRITE,
                            NULL,
                            OPEN_EXISTING,
                            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
                            NULL);
 

Step 5: Check for matching HID attributes.
We check the attributes of the newly opened device to verify it’s a PowerMate input device.


HIDD_ATTRIBUTES hidAttr;
BOOLEAN result = HidD_GetAttributes(hDevice, &hidAttr);

if ((int)HidAttributes::ProductID == hidAttr.ProductID &&
    (int)HidAttributes::VendorID  == hidAttr.VendorID)
{
    // ...

    inputThread = gcnew Thread(gcnew ThreadStart(this, &PowerMate::InputThread));

    inputThread->Priority = ThreadPriority::Normal;
    inputThread->Start();

    return true;
}
 

When a PowerMate input device is found, an input thread is started for event notification. We”ll have a look at the input thread shortly, but first two-stage destruction:


publicvoid Shutdown()
{
    if (nullptr != exitEvent)
    {
        exitEvent->Set();
        inputThread->Join();
    }

    if (NULL != handleToDevice)
        CloseHandle(handleToDevice);

    Process^ p = Process::Start(
        "C:Program FilesGriffin TechnologyPowerMatePowerMate.exe");

    HWND hWndTaskBar   = FindWindowEx(NULL, NULL, L"Shell_TrayWnd", NULL);
    HWND hWndTrayNotify= FindWindowEx(hWndTaskBar, NULL, L"TrayNotifyWnd", NULL);
    HWND hWndSysPager  = FindWindowEx(hWndTrayNotify, NULL, L"SysPager", NULL);
    HWND hWndToolBar   = FindWindowEx(hWndSysPager, NULL, L"ToolbarWindow32", NULL);

    RECT rect;
    ::GetClientRect(hWndToolBar, &rect);

    for (WORD x = 0; x < rect.right; x += 8)
    {
        ::SendMessage(hWndToolBar,
                      WM_MOUSEMOVE,
                      0,
                      MAKELPARAM(x,0));
    }
}
 

Shutdown begins by signaling the exit event. Join blocks the calling thread until the input thread terminates.
Next, we start a new instance of the PowerMate Control Panel (after shutting it down during Initialization). It”s hardwired to the default installation directory. However, it’s advisable that you pull this path out of the registry. The InstallDir key is located under: HKEY_LOCAL_MACHINESOFTWAREGriffin TechnologyPowerMate1.5 and you can use regedit to verify this.

The last part is silly and if you have a better way to fix it please let me know. The icon in the task notification area does not update automatically. Here, we simulate a mouse traveling across the notification area to force an update.

The input thread drops into a while loop that only breaks when it receives an exit event. The exit event is checked during wait timeouts which occur every 2000 milliseconds. With each iteration a call to ReadFile is made. The OVERLAPPED structure is used for asynchronous I/O. The event member of the OVERLAPPED structure is signaled when the read operation is complete. Upon a successful read, a report buffer consisting of eight characters is returned. Indices in the report buffer are checked for a button or rotational event and the corresponding delegate is fired.


privatevoid InputThread()
{
    char reportBuffer[8] = {0};
    DWORD dwBytesRead = 0;
    BOOL result = FALSE;

    HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

    OVERLAPPED overLap;
    ZeroMemory( &overLap, sizeof(overLap));
    overLap.hEvent = hEvent;

    while(true)

    {
        result = ReadFile(handleToDevice,
                          reportBuffer,
                          sizeof(reportBuffer),
                          &dwBytesRead,
                          &overLap);

        DWORD dw = WaitForSingleObject(hEvent, 2000);

        switch(dw)
        {
            case WAIT_OBJECT_0:
            {
                // test for pushbutton
                if (reportBuffer[1] == 1)
                {
                    ButtonState bs = ButtonState::Down;
                    EventsHelper::Fire(buttonDelegate, bs);
                }
                else if (reportBuffer[2] == 0 && reportBuffer[1] == 0)
                {
                    ButtonState bs = ButtonState::Up;
                    EventsHelper::Fire(buttonDelegate, bs);
                }

                // test for knob rotation
                if (reportBuffer[2] != 0)
                {
                    rotationValue += reportBuffer[2];
                    if (rotationValue < rotationLowerBound)
                    {
                        rotationValue = rotationLowerBound;
                        break;
                    }

                    if (rotationValue > rotationUpperBound)
                    {
                        rotationValue = rotationUpperBound;
                        break;
                    }

                    EventsHelper::Fire(rotationDelegate,
                                       (reportBuffer[2] < 0) ?
                                           RotationalDirection::Left :
                                           RotationalDirection::Right,
                                       rotationValue);

                } // end ifbreak;

            case WAIT_TIMEOUT:
            {
                if (exitEvent->WaitOne(20,false))
                {
                    CloseHandle(hEvent);
                    return;
                }
            } break;

        } // end switch

// end while

// end method
 

The EventsHelper class continues to publish events even if a subscriber throws an exception:


public ref class EventsHelper
{
    publicstatic void Fire(Delegate^ del, ... array^ args)
    {
        if (nullptr == del)

            return;

        array^ delegates = del->GetInvocationList();
        for each (Delegate^ sink in delegates)
        {
            try
            {
                sink->DynamicInvoke(args);
            }
            catch(Exception^ e)
            {

            }
        }
    }
};
 

Finally, we can start manipulating properties of the PowerMate input device. Setting various properties involve the same basic steps:

  • Filling out report buffers and transmitting them.
  • Receiving report buffers and acting on them.

For example, getting or setting the LED brightness:


publicproperty Byte LedBrightness
{
    void set(Byte value)
    {
        if (NULL != handleToDevice)
        {
            HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

            OVERLAPPED overLap;
            ZeroMemory(&overLap, sizeof(overLap));
            overLap.hEvent = hEvent;

            UCHAR reportBuffer[2];
            reportBuffer[0] = 0;
            reportBuffer[1] = value;
            DWORD dwBytesTransmitted = 0;

            BOOL result = WriteFile(handleToDevice,
                                    reportBuffer,
                                    sizeof(reportBuffer),
                                    &dwBytesTransmitted,
                                    &overLap);

            DWORD dw = WaitForSingleObject(hEvent, 42);

            switch(dw)
            {
                case WAIT_OBJECT_0:
                    break;

                case WAIT_TIMEOUT:
                    break;
            }

            CloseHandle(hEvent);
        }
    }

    Byte get()
    {
        UCHAR reportBuffer[7] = { 0 };

        if (NULL != handleToDevice)
        {
            BOOLEAN error = HidD_GetInputReport(handleToDevice,
                                                reportBuffer,
                                                sizeof(reportBuffer));

            if( FALSE == error )
                Trace::WriteLine("Failure to get input report - brightness");
        }

        return reportBuffer[4];
    }
}
 

The two other properties are ”pulse on” and ”pulse speed”. Please reference the code for implementation details.

Those are the basics of PowerMate programming. Special thanks to Dustin at Griffin for making this possible. The code still needs refactoring and more support for error handling. However, it’s surely enough to get you started. You can download the source here.