Author Archives: bverhue

A G2 mini editor for Android part 2

Here is some info about beta version (0.2) of the Android G2 editor I’m making. There is also a download link at the bottom of this page if you want to try it out.

The 0.1 version was about getting the USB interface working. You can read the technical details here.

In this version 0.2 i have made a lot of effort getting the performance up to an acceptable level and to add functionality and improve the user interface.

Important: To connect to a G2 synth from your Android device, your device needs to supports USB Host mode and you also need an OTG cable.

So, if your device meets these requirements, you can it connect to the G2, otherwise you can only try the application ofline. I’m using the Acer A1 810 myself, which can be bought for about 150 euro’s. Your device should have a screen size of at least 1024×600 to fit the application.

Because the USB identity of the G2 is associated with the application, there will automatically appear a message on the screen if you connect the G2 to your device:

“Open G2_mini_editor when this USB device is connected?”


Press OK and the application should start, it takes about 15 seconds to load the application.

The main screen looks like the one below, I’ll explain a bit of the user interface in a second. First you will see the green led light up as the application downloads the data, patches and so on from the G2.

You can also see the messages that are exchanged between de application and the G2 on the little log line. It ends with message “Start communication”. This is the command that starts the led and volume data stream from the G2 and is the last message in the initialisation fase.

So, about the user interface, I have tried a couple of different versions and ended up with the following. The difficulty is of course fitting all functionality on a small screen and also to keep the performance of the application on an acceptable level.

It is a tab based application, with four tabs: Perf (performance), Patch, Patch settings and Knobs. On the left there are four buttons (A, B, C, D) with which you can select the current slot.


The “Performance tab” shows the performance settings and the main settings of all four slots. It is not complete yet and not alle buttons are working at the moment, but from top-left to bottom-right the controls are the following:

  • USB activity indicator led
  • Synth button with the name of the connected G2. Later on you will get the “Synt settings” form if you press this button.
  • Performance button with the name of the current performance. If you press this button, you can select another performance from the G2 memory banks.
  • Master clock
  • Master clock run button
  • Keyboard split button (not working at the moment)
  • Perf mode button

Then for each slot

  • Patch button with the name of the current patch. If you press this button you can select another patch from the G2 memory banks.
  • Variation radio buttons
  • Volume slider
  • Mute button
  • Keyboard enable button
  • Hold enable button

On the bottom there is a keyboard. This will send note-on note-off messages over USB, just like the keyboard floater in the original Clavia editor. Sadly, the G2 only supports mono-key over USB.

The application supports multi-touch (thanks to Iztok Kacin), but because of above restriction, you can’t play chords on the keyboard, this will cause one key to hang. But you can hold a key an for example move a slider or select another variation.

If you press the Performance button or one of the Patch buttons, the “Patch select” window appears, which looks like this for now.


On the left the banks with patches on the right the banks with performances.

The second tab on the main screen is the “Patch tab”. It shows a simplified representation of the patch in the slot selected on the Slot selection buttons on the left. So in this case it is the patch of slot C, in the VA section.


You will notice that only modules, connectors and cables are shown. That is to speed up rendering of the picture and also because the controls would be much too small to edit.

It is still a bit slow, which will be evident if you play the keyboard in this screen. It has a distinct lag, so some work still to do here.

If you tap on a module, that module is shown full screen. Here you can edit the parameters of the module.


In future you will be able to add/delete modules on the patch window and probably add cables. But that is another user interface challange I haven’t started on yet, maybe in the next version.

The third tab is the “Patch settings” tab. This will be familiar from the original Clavia editor. You select the active slot with the “Slot selection” buttons on the left.


The last tab is the “Knobs tab”. This should also be familiar.


So that is basically all for now. If you want to try out this version you can download it here. It is only a beta so be aware that is contains bugs and also functionality is not complete.

For installation, just extract the apk from the zip and install it on your Android device.


A G2 mini editor for Android

This is a start for a simple G2 editor for Android. I tried to run the G2_editor_FMX on my tablet but it was too slow because of all the controls and the user interface not suited for a small screen. The G2_editor_FMX is more suited for a desktop computer or a high-end tablet with a big screen.

This new application “G2 mini editor” has less functionality (for now). The important thing is that response time is ok, and you can operate it on a small screen. I’m using a Acer A1-810. The other important thing is that the tablet must support “USB Host mode”.

The application only has four screens at the moment. The first screen is the “Performance view”. Here you can load patches and performances from the memory banks and set volume an variation. You can also set the master clock on this form.


When you press on one off the buttons with the patch name or the button with the performance name, you open the “Patch select view”. On the left you can select a bank and on the right is a list with patches/performances in that bank. You load the selected patch by pressing the Ok button.


Then back in the Performance view, there are tabs on the top, which lets you select the four slots A, B, C or D. The patch is only shown in a simplified manner, to reduce load on the processor. For the moment it only gives an overview of the modules in the patch.


Finally when you tap on a module, it opens in a new window. The module is shown in full screen, to enable operating all the controls.


So, its not really an editor at the moment, but more a controller. But maybe I can turn it into a real editor, when I figure out how to implement the cable-drawing functionality.

I have an apk file here if you want to try it out. So you copy the apk file to your tablet and install it. Your tablet should support “USB Host mode” and you need a “USB OTG cable”. Connect this cable directly to the G2 and turn it on after you installed the application.

The moment the tablet detects the G2, it should prompt with a message asking if you want to start the g2_mini_editor, press “Always” or “Just once”. Then the application should start. After that, in the application, press the connect button.

You can dowload the application version 0.01 here. Note that this is experimental software that you can use but at your own risk.


Delphi Android USB Interface with the G2

I first tried to use Libusb to connect my Android tablet with the G2. I managed to compile the libusb sources for Android and call it from the application, only to run into the “No permissions” error on trying to open the device.

There is no easy solution for this at the moment, other than havng to root the device and do other complex things, which very much narrows down the public who could eventually use the application.

So I tried the other method, using the “Java native interface”, which turned out to be very easy. Here is an example application which uses this method to interface over USB.

It involves 3 steps:

  1. Writting the JNI API header unit
  2. Writing the application
  3. Defining a device filter in the AndroidManifest.template.xml file

There is one important requirement: the Android device must support “Host mode” and you should use a USB OTG cable to connect to the G2.

Host mode means that the Android device can play the role of host to the usb slave device (the G2) and the OTG cable, because of special wiring, triggers the device into host mode.

First the API header unit for the USB functions has to be created. I used the example over here:, which  deals with the Bluetooth interface as an example.

I’ve not exposed all classes or methods at the moment, just the ones I needed for my application.

unit Androidapi.JNI.USB;

// (c) B.J.H. Verhue 2014
// JNI USB API converted from api-versions.xml


// =============================================================================
//                                 UsbEndPoint
// =============================================================================

  JUsbEndPoint = interface;
  JUsbEndPointClass = interface(JObjectClass)

  JUsbEndPoint = interface(JObject)
    function init:JUsbEndPoint; cdecl;
    function getAddress:integer; cdecl;
    function getAttributes:integer; cdecl;
    function getDirection:integer; cdecl;
    function getEndpointNumber:integer; cdecl;
    function getInterval:integer; cdecl;
    function getMaxPacketSize:integer; cdecl;
    function getType:integer; cdecl;

  TJUsbEndPoint = class(TJavaGenericImport<JUsbEndPointClass, JUsbEndPoint>) end;

// =============================================================================
//                                 UsbInterface
// =============================================================================

  JUsbInterface = interface;
  JUsbInterfaceClass = interface(JObjectClass)

  JUsbInterface = interface(JObject)
    function init:JUsbInterface; cdecl;
    function getEndpoint(i : integer): JUsbEndPoint; cdecl;
    function getEndpointCount: integer; cdecl;
    function getId: integer; cdecl;
    function getInterfaceClass: integer; cdecl;
    function getInterfaceProtocol: integer; cdecl;
    function getInterfaceSubclass: integer; cdecl;

  TJUsbInterface = class(TJavaGenericImport<JUsbInterfaceClass, JUsbInterface>) end;

// =============================================================================
//                               UsbDeviceConnection
// =============================================================================

  JUsbDeviceConnection = interface;
  JUsbDeviceConnectionClass = interface(JObjectClass)

  JUsbDeviceConnection = interface(JObject)
    function init:JUsbDeviceConnection; cdecl;
    function bulkTransfer(UsbEndpoint: JUsbEndpoint; data: TJavaArray<Byte>; length : integer; timeout : integer): integer; cdecl;
    function claimInterface(UsbInterface: JUsbInterface; ForceClaim: boolean): boolean; cdecl;
    procedure close; cdecl;
    function releaseInterface(UsbInterface: JUsbInterface): boolean; cdecl;

  TJUsbDeviceConnection = class(TJavaGenericImport<JUsbDeviceConnectionClass, JUsbDeviceConnection>) end;

// =============================================================================
//                                   UsbDevice
// =============================================================================

  JUsbDevice = interface;
  JUsbDeviceClass = interface(JObjectClass)

  JUsbDevice = interface(JObject)
    function getProductId:integer; cdecl;
    function getVendorId:integer; cdecl;
    function getInterface(i: integer):JUSBInterface; cdecl;
    function getInterfaceCount: integer; cdecl;

  TJUsbDevice = class(TJavaGenericImport<JUsbDeviceClass, JUsbDevice>) end;

// =============================================================================
//                                 UsbManager
// =============================================================================

  JUsbManager = interface;
  JUsbManagerClass = interface(JObjectClass)

  JUsbManager = interface(JObject)
    function getDeviceList:JHashMap; cdecl;
    function hasPermission(UsbDevice:JUsbDevice):boolean; cdecl;
    function openDevice(UsbDevice:JUsbDevice):JUsbDeviceConnection; cdecl;

  TJUsbManager = class(TJavaGenericImport<JUsbManagerClass, JUsbManager>) end;



Second writing the application.  I’ve made a simple Android application in XE5 bases on a blank mobile form.  The application has four buttons:

  1. List devices, this lists all connected USB devices
  2. Open, this opens the G2 devivce, if it is found
  3. Message, this sends an “Init” message to the G2
  4. Close, this closes the device

The messages are shown in a Memo control.

Here is the code


unit UnitUSBTestJNI;

// (c) B.J.H. Verhue 2014
// G2 USB communication using JNI API DEMO


  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Layouts,
  FMX.Memo, FMX.StdCtrls,

  // Thread for receiving messages from G2
  TUSBThread = class(TThread)
    [Weak] FUsbDeviceConnection : JUSBDeviceConnection;
    [Weak] FUsbEPII : JUSBEndPoint;
    [Weak] FUsbEPBI : JUSBEndPoint;
    FLogMessage : string;
    FBytesRead : integer;
    FBBuffer : TJavaArray<Byte>;
    procedure Execute; override;
    constructor Create( CreateSuspended: Boolean);
    destructor Destroy; override;

    procedure ProcessMessage;
    procedure WriteLog;
    procedure DumpIMessage;
    procedure DumpBMessage;

    property UsbDeviceConnection : JUSBDeviceConnection read FUsbDeviceConnection write FUsbDeviceConnection;
    property UsbEPII : JUSBEndPoint read FUsbEPII write FUsbEPII;
    property UsbEPBI : JUSBEndPoint read FUsbEPBI write FUsbEPBI;

  TForm1 = class(TForm)
    Panel1: TPanel;
    bListDevices: TButton;
    Memo1: TMemo;
    bOpen: TButton;
    bMessage: TButton;
    bClose: TButton;
    procedure bListDevicesClick(Sender: TObject);
    procedure bOpenClick(Sender: TObject);
    procedure bCloseClick(Sender: TObject);
    procedure bMessageClick(Sender: TObject);
    FUsbActive : boolean;
    FUsbThread : TUSBThread;
    FUsbManager : JUSBManager;
    FUsbDevice : JUSBDevice;
    FUsbInterface : JUSBInterface;
    FUsbEPII, FUsbEPBI, FUsbEPBO : JUSBEndPoint;
    FUsbDeviceConnection : JUSBDeviceConnection;
    function GetUsbActive: boolean;
    procedure SetUsbActive(const Value: boolean);
    procedure DumpMessage( data : TJavaArray<Byte>; size : integer);
    property UsbActive : boolean read GetUsbActive write SetUsbActive;

  Form1: TForm1;


{$R *.fmx}

function CrcClavia( Seed: Integer; aVal: Integer): Word;
   i    : Integer;
   aCrc : Integer;
   k    : Integer;
  // Calculates the G2 checksum for messages

   k    := ((( Seed shr 8) xor aVal) and 255) shl 8;
   aCrc := 0;
   for i := 1 to 8
   do begin
     if ( aCrc xor k) and $8000 <> 0
     then aCrc := ( aCrc shl 1) xor $1021
     else aCrc := aCrc shl 1;
     k := k shl 1;
   Result := (( Seed shl 8) xor aCrc) and $ffff;

procedure TForm1.bListDevicesClick(Sender: TObject);
var JavaObject : JObject;
    DeviceList : JHashMap;
    Device : JUSBDevice;
    i : Jiterator;
    s : JString;
  // Device discovery...

  // Get pointer to UsbManager
  JavaObject := SharedActivityContext.getSystemService(TJContext.JavaClass.USB_SERVICE);
  FUsbManager := TJUSBManager.Wrap((JavaObject as ILocalObject).GetObjectID);

  // Get a list of connected slave devices
  DeviceList := FUsbManager.getDeviceList;
  s := DeviceList.toString;

  // Get pointer to G2 Device
  FUsbDevice := nil;
  i := DeviceList.values.iterator;
  while i.hasNext do begin
    Device := TJUSBDevice.Wrap(( as ILocalObject).GetObjectID);
    if (Device.getVendorId = 4092) and (Device.getProductId = 2) then
      FUsbDevice := Device;
    Memo1.Lines.Add('VendorID ' + IntToStr(Device.getVendorId) + ', ProductID ' + IntToStr(Device.getProductId));

  if assigned(FUsbDevice) then
    bOpen.Enabled := assigned(FUsbDevice);

procedure TForm1.bCloseClick(Sender: TObject);
  if UsbActive then
    UsbActive := False;

procedure TForm1.bMessageClick(Sender: TObject);
var bytes_written, size, i : integer;
    crc : Word;
    Buffer : TJavaArray<Byte>;
  // Send "Init" message to G2

  if assigned(FUsbDeviceConnection) then begin

    Buffer := TJavaArray<Byte>.Create(5);
      Size := 1 + 2 + 2;

      Buffer.Items[0] := size div 256;
      Buffer.Items[1] := size mod 256;
      Buffer.Items[2] := $80;

      // Calc CRC
      Crc := 0;
      i := 2;
      while i < (Size-2) do begin
        Crc := CrcClavia(Crc, Buffer.Items[i]);

      Buffer.Items[3] := crc div 256;
      Buffer.Items[4] := crc mod 256;

      bytes_written := FUsbDeviceConnection.bulkTransfer(FUsbEPBO, Buffer, Size, 100);

procedure TForm1.bOpenClick(Sender: TObject);
  UsbActive := True;

procedure TForm1.DumpMessage(data: TJavaArray<Byte>; size : integer);
var p, i, c : integer;
    char_line, line : string;
  // Dump message in HEX and Char values

    c := 0;
    i := 0;
    p := 0;
    line := '';
    char_line := '';;
    while (i<size) do begin
      if c < 16 then begin
        line := line + IntToHex(data.Items[i], 2) + ' ';
        if data.Items[i] >= 32 then
          char_line := char_line + chr(data.Items[i])
          char_line := char_line + '.';
      end else begin
        Memo1.Lines.Add(IntToHex(p, 6) + ' - ' + line + ' ' + char_line);
        p := i;
        c := 0;
        line := '';
        char_line := '';
    if c <> 0 then
      Memo1.Lines.Add(IntToHex(p, 6) + ' - ' + line + stringofchar(' ', 16*3 - Length(line) + 1) + char_line);

function TForm1.GetUsbActive: boolean;
  result := FUsbActive;

procedure TForm1.SetUsbActive(const Value: boolean);
  if Value then begin

    // Activate the USB inteface with G2

    // Get interface
    Memo1.Lines.Add('# Interfaces ' + IntToStr(FUsbDevice.getInterfaceCount));

    FUsbInterface := FUsbDevice.getInterface(0);
    Memo1.Lines.Add('# Endpoints ' + IntToStr(FUsbInterface.getEndpointCount));

    // Get 3 endpoints
    FUsbEPII := FUsbInterface.getEndpoint(0);
    Memo1.Lines.Add('Endpoint ' + IntToStr(FUsbEPII.getEndpointNumber));

    FUsbEPBI := FUsbInterface.getEndpoint(1);
    Memo1.Lines.Add('Endpoint ' + IntToStr(FUsbEPBI.getEndpointNumber));

    FUsbEPBO := FUsbInterface.getEndpoint(2);
    Memo1.Lines.Add('Endpoint ' + IntToStr(FUsbEPBO.getEndpointNumber));

    // Check permisions
    if FUsbManager.hasPermission(FUsbDevice) then begin
      Memo1.Lines.Add('Permissions o.k.');
    end else begin
      raise Exception.Create('No permission...');

    // Open device
    FUsbDeviceConnection := FUsbManager.openDevice(FUsbDevice);
    if not assigned( FUsbDeviceConnection) then
      raise Exception.Create('Failed to open device.');

    if not FUsbDeviceConnection.claimInterface(FUsbInterface, True) then
      raise Exception.Create('Failed to claim interface.');

    FUsbActive := Value;

    // Start listening thread
    FUsbThread := TUsbThread.Create(True);
    FUsbThread.FUsbDeviceConnection := FUsbDeviceConnection;
    FUsbThread.FUsbEPII := FUsbEPII;
    FUsbThread.FUsbEPBI := FUsbEPBI;
  end else begin

    // Deactivate the USB connection

    FUsbActive := Value;

    if assigned(FUsbDeviceConnection) then begin

      // Release interface
      if not FUsbDeviceConnection.releaseInterface(FUsbInterface) then
        Memo1.Lines.Add('Failed to release the interface');

      // Close device and free the thread
      if assigned(FUsbThread) then begin
      end else

      Memo1.Lines.Add('Device is closed');

{ TUSBThread }

constructor TUsbThread.Create( CreateSuspended: Boolean);
  FreeOnTerminate := False;

  FIBuffer := TJavaArray<Byte>.Create(16);
  FBBuffer := TJavaArray<Byte>.Create(8192);

destructor TUsbThread.Destroy;


procedure TUsbThread.Execute;
var size : integer;
  FLogMessage := 'Thread started.';

  // The G2 sends first a short message over the interrupt endpoint of max 16 bytes
  // This may be followed by a longer message (extended message)

  while assigned(FUsbDeviceConnection) and (not Terminated) do begin
    FBytesRead := FUsbDeviceConnection.bulkTransfer(FUsbEPII, FIBuffer, 16, 0);

    if FBytesRead > 0 then begin


      if FIBuffer.Items[0] and $f = 1 then begin
        // Extended message
        size := (FIBuffer.Items[1] shl 8) or FIBuffer.Items[2];

        FLogMessage := 'Extended message, size ' + IntToStr(size);

        FBytesRead := FUsbDeviceConnection.bulkTransfer(FUsbEPBI, FBBuffer, size, 0);

        FLogMessage := 'Extended message, bytes read ' + IntToStr(FBytesRead);

      end else begin
        // Embedded message
  FLogMessage := 'Thread terminated.';

procedure TUsbThread.ProcessMessage;
  // Do something with the message...

procedure TUsbThread.WriteLog;

procedure TUsbThread.DumpIMessage;
  Form1.DumpMessage(FIBuffer, FBytesRead);

procedure TUsbThread.DumpBMessage;
  Form1.DumpMessage(FBBuffer, FBytesRead);



Finally we have to define a device filter in the “AndroidManifest.template.xml” file. This ensures that you get the necessary permissions for opening the device. Also, this enables automatic launch of the application when you plug in the device in your Android tablet!

First you have to make a little xml file, containing the vendor id and product id of the device. In case of the G2 synth, this file looks like this:

<?xml version="1.0" encoding="UTF-8"?>
    <usb-device vendor-id="4092" product-id="2" class="0" subclass="0" protocol="0" />

Save this file as “device_filter.xml” and add it to the project.

You also have to deploy this file to the Android device, so put it into the Deployment manager, with remote path “res\xml”.


Next edit the file “AndroidManifest.template.xml” which should be in your project folder after compiling the application.

Put in

<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
                android:resource="@xml/device_filter" />

As a child in the “activity” element, and put

<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />

As a child to the “intent-filter” element. So the dile should look something like this:

<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android=""

    <!-- This is the platform API where NativeActivity was introduced. -->
    <uses-sdk android:minSdkVersion="%minSdkVersion%" />
    <application android:persistent="%persistent%" 
        <!-- Our activity is a subclass of the built-in NativeActivity framework class.
             This will take care of integrating with our NDK code. -->
        <activity android:name="com.embarcadero.firemonkey.FMXNativeActivity"
            <!-- Tell NativeActivity the name of our .so -->
            <meta-data android:name=""
                android:value="%libNameValue%" />
            <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
                android:resource="@xml/device_filter" />
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
        <receiver android:name="com.embarcadero.firemonkey.notifications.FMXNotificationAlarm" />
<!-- END_INCLUDE(manifest) -->

Ok. So now you should be able to deploy the application to the Android device and connect to the G2.