Introduction
I have always struggled with finding proper documentation for hardware controllers in my DJ software applications. Usually companies want to keep the technical details about how to interface with their hardware controllers a secret because they don't want competition to be able to support their hardware. This is understandable, but also frustrating for smaller software companies that do not have the resources to be able to create and distribute their own hardware controllers. Since I have a small dj software business and PCDJ would not give out any documentation on how to support their hardware controller I decided to reverse engineer the DAC2 and the Hercules DJ Console in order to add support for these great hardware controllers in my own DJ applications.
Reverse Engineering the Controllers
The first thing you have to do is purchase the controller. So the first thing I did was I went on ebay and purchased a DAC-2 and a Hercules DJ Console. They were fairly expensive about $400 CA for the DAC-2 and about $300 CA for the Hercules DJ Console. So the first one I tackled was the DAC-2 since it seem easier as it uses the RS232 serial chipset.
DAC-2
To find out what hex code each button/slider/jog wheel sent back through the serial port, I installed and RS-232 sniffer or port monitor program. The one I used was the RS-232 Hex Com Tool v5.01. The first thing I had to do was find out what the correct port settings were for the DAC-2. I found out by trial and error that the port settings are:
- Baud Rate: 57600
- Parity: None
- Data Bits: 8
- Stop Bits: 1
- Flow: None
This is important because if these settings are wrong, then the hex codes that the DAC-2 sends across the serial port will come back incorrect and most likely not unique therefore useless.
So now we have the serial port monitor setup so we can start pushing buttons, sliding sliders, and moving jog wheels and see what we receive in our serial port monitor. Then you just press each button, slide each slider, move each jog wheel and map out all the hex codes for the buttons and map out all of the hex ranges for the sliders and jog wheels until you have them all for each Deck.
So now we have all mapped out all of the hex codes that can be received from the DAC-2, but what about the hex codes that the DAC-2 accepts to control LEDs and the digital display panels? Well that's where it gets a little tricky. Here is what I did. I downloaded a trial version of PCDJ FX and ran the program with DAC-2 support enabled as well as ran the RS-232 Hex Com Tool at the same time. Then I pushed buttons in PCDJ FX that would toggle each led and change each digital display. Now this is VERY VERY tedious and boring and takes for ever, but I got through it and mapped out all of the possible hex codes I could transmit to the DAC-2.
I mapped everything out to a Word Document that you can see here DAC-2 Specifications Document.
Hercules DJ Console
Next was the Hercules DJ Console. Now there are actually three versions of the Hercules DJ Console, the Hercules DJ Console, the Hercules DJ Control MP3, and the Hercules DJ Console MK2.
The Hercules DJ console is registered as a MIDI controller so I could use MIDI codes to add support and it is also a DirectX input device so I could use the joystick code from the DXSDK, or I could use Human Device Interface or USB.
- I tried using MIDI, but it seemed that there was no way to control the LEDs using this method. Also you had to configure your Hercules DJ Console software as a MIDI controller in order for it to work, and most users will not know how to do this. Also the MIDI codes were different between all 3 versions of the Hercules DJ Console. So I scrapped this idea very fast as it would cause me many headaches.
- I thought about using DirectInput, but then I remembered how much I hate using DirectX. Also it didn't seem like this is how my competition was doing it. Although, somehow my competition got an SDK. I couldn't even BUY an SDK from Hercules....
- So after much research, it seemed that HID/USB was the way to go because I could control the LEDs and respond to all control events easily for all 3 controllers with minimal changes to my code. Also, it would ALWAYS work as long as the Hercules was plugged in and the drivers were installed (no need for the user to have a special configuration)
So I found out that each of the 3 controllers had its own product id, but they obviously all had the same vendor id as shown below by using a USB properties tool for each device.
//Hercules DJ Console
//int VendorID = 0x06F8;
//int ProductID = 0xB000;
//Hercules DJ Console MK2
//int VendorID = 0x06F8;
//int ProductID = 0xB100;
//Hercules DJ Control MP3
//int VendorID = 0x06F8;
//int ProductID = 0xD001;
Once I knew this, I just had to figure out all of codes that the Hercules DJ Console could receive and transmit and then I hoped that it would work for the other 3 controllers providing I supplied the proper product id using the HID code from the Microsoft Windows DDK (and btw the codes were all the same as I suspected!!).
So then I needed to figure out how to use HID and I found some source code at this website that allowed me to map out all of the codes that could be received from the HerculesDJ Console. I also used this source code to control the Hercules DJ Console in the DLL library that we are going to create next.
The code is as listed below:
const int LeftPlay = 0x80000000;
const int LeftCue = 0x00010000;
const int LeftTrackPrev = 0x00040000;
const int LeftTrackNext = 0x00080000;
const int LeftPitchBendPlus = 0x00000400;
const int LeftPitchBendMinus = 0x00000800;
const int LeftPreview = 0x00001000;
const int LeftOne = 0x00400000;
const int LeftTwo = 0x00200000;
const int LeftThree = 0x00100000;
const int LeftSelectFX = 0x40000000;
const int LeftMasterTempo = 0x00002000;
const int LeftAutoBeat = 0x00020000;
const int LeftMouseButton = 0x00000004;
const int RightPlay = 0x02000000;
const int RightCue = 0x04000000;
const int RightTrackPrev = 0x10000000;
const int RightTrackNext = 0x20000000;
const int RightPitchBendPlus = 0x00004000;
const int RightPitchBendMinus = 0x00008000;
const int RightPreview = 0x00000001;
const int RightOne = 0x00800000;
const int RightTwo = 0x00000100;
const int RightThree = 0x00000200;
const int RightSelectFX = 0x01000000;
const int RightMasterTempo = 0x00000002;
const int RightAutoBeat = 0x08000000;
const int RightMouseButton = 0x00000008;
//LED Codes DeckA
Flash Play LED - 0x000002
Play LED - 0x000100
Cue LED - 0x000800
Auto Beat - 0x001000
Monitor - 0x000200
Master Tempo - 0x010000
FX - 0x040000
CueFX - 0x800000
LoopFX - 0x004000
//LED Codes DeckB
Flash Play LED - 0x000001
Play LED - 0x400000
Cue LED - 0x200000
Auto Beat - 0x002000
Monitor - 0x000400
Master Tempo - 0x020000
FX - 0x080000
CueFX - 0x100000
LoopFX - 0x008000
Creating the DLL Libraries for Controlling the Hardware
DAC-2
Now that I had all of the codes that the DAC-2 could receive and transmit mapped out, it was time to write the code that would actually allow me to add support for the controller in my own DJ application.
So I went to the code project and found a class called CSerialPort
by Eric Woodruff on the internet that supported overlapped serial port communication. I used this to do all the serial port communication.
Then I started a new DLL project based off of one of my own articles called the Super Easy DLL. I then added in the CSerialPort
class and then begin coding. There is way too much code to display so you will have to go the example source code at the top and have a look.
Hercules DJ Console
Now that I had all of the codes that the Hercules DJ Console could receive and transmit mapped out it was time to write the code that would actually allow me to add support for the controller in my own DJ application.
So I went some source code here that was available on the internet that supported HID communication. I used this to do all the USB communication.
Then I started a new DLL project based off of one of my own articles called the Super Easy DLL. I then added in the HID class and then began coding. There is way too much code to display so you will have to go the example source code at the top and have a look.
DLL Structures and Implementation
I designed the DLL libraries so that they would be easy to use for developers that want to add support for the Hercules DJ Console or the DAC-2 hardware controllers. Basically I just needed a function to detect and initialize the controllers and then a series of functions to control the output and input. So I followed the structure used be the BASS sound engine library found and http://www.un4seen.com/ because it is easy to use and I like that structure.
DAC-2 Functions
DAC2_ErrorGetCode
DAC2_Init
DAC2_Free
DAC2_AutoInit
DAC2_EventCallbackSet
DAC2_DeckA_SetCueNumber
DAC2_DeckB_SetCueNumber
... (many more functions, but too many to list)
Example Code for using the library:
BOOL bSuccess = DAC2_AutoInit(); if(bSuccess)
{
DAC2_EventCallbackSet((DAC2PROC*)&DAC2DeckAHandler,
(DAC2PROC*)&DAC2DeckBHandler, (DWORD)this);
}
void CALLBACK DAC2DeckAHandler(DWORD dwAction, DWORD dwValue, DWORD user)
{
if(dwAction == DAC2_LOAD_DOWN)
{
MessageBox("Load Button Down", "Load Button Down", MB_ICONINFORMATION|MB_OK);
}
else if(dwAction == DAC2_LOAD_UP)
{
MessageBox("Load Button Up", "Load Button Up", MB_ICONINFORMATION|MB_OK);
}
}
void CALLBACK DAC2DeckBHandler(DWORD dwAction, DWORD dwValue, DWORD user)
{
if(dwAction == DAC2_LOAD_DOWN)
{
MessageBox("Load Button Down", "Load Button Down", MB_ICONINFORMATION|MB_OK);
}
else if(dwAction == DAC2_LOAD_UP)
{
MessageBox("Load Button Up", "Load Button Up", MB_ICONINFORMATION|MB_OK);
}
}
...
DAC2_SetPlayLight(1);
DAC2_DeckA_SetCueNumber(15);
Hercules DJ Console Functions
HERC_ErrorGetCode
HERC_Init
HERC_Free
HERC_EventCallbackSet
HERC_SetLED
if(HERC_Init())
{
HERC_EventCallbackSet((HERCPROC*)&HERCDeckAHandler,
(HERCPROC*)&HERCDeckBHandler, (DWORD)this);
}
void CALLBACK HERCDeckAHandler(DWORD dwAction, DWORD dwValue, DWORD user)
{
if(dwAction == HERC_MODE && dwValue == 127)
{
MessageBox("Load Button Down",
"Load Button Down", MB_ICONINFORMATION|MB_OK);
}
else if(dwAction == HERC_MODE && dwValue == 0)
{
MessageBox("Load Button Up", "Load Button Up", MB_ICONINFORMATION|MB_OK);
}
}
void CALLBACK HERCDeckBHandler(DWORD dwAction, DWORD dwValue, DWORD user)
{
if(dwAction == HERC_MODE && dwValue == 127)
{
MessageBox("Load Button Down",
"Load Button Down", MB_ICONINFORMATION|MB_OK);
}
else if(dwAction == HERC_MODE && dwValue == 0)
{
MessageBox("Load Button Up", "Load Button Up", MB_ICONINFORMATION|MB_OK);
}
}
...
HERC_SetLed(0, HERC_LED_PLAY, TRUE);
HERC_SetLed(1, HERC_LED_PLAY, TRUE);
Conclusion
I know that many people out there think that interfacing with hardware is complicated and it is especially when you have no documentation. However, it is not impossible to get these things to work. I also know that almost nobody shares source code about these types of things so I decided to because this took me probably over 6 months of development time to figure out and create.
I also included source files for the help documentation I created for the Hercules DJ Console and DAC2 libraries.
Credits