Skip to content

Making a GUI in the TympanRemote App

hgeithner-creare edited this page Aug 17, 2021 · 16 revisions

The TympanRemote App is unique because it allows you, the programmer of the Tympan, to create a graphical interface on the mobile device. You program the Tympan and your code on the Tympan tells the mobile device what to display. You do not need to know how to program for Android or iOS, you just need to know how to program for the Tympan (ie, Arduino). Magic!

The TympanRemote app is available for free on the Android Play Store and the Apple App Store.

Making a GUI in the TympanRemote App

We have a new, easier way to add a GUI to your programs! A GUI layout for the TympanRemote App is composed of three types of widgets: pages, cards (a grouping of buttons), and buttons.

If you are feeling adventurous, take a look at the BasicGain_wApp example sketch and try making your own GUI. First, you will need to define the GUI by using pages, cards, and buttons, like this example:

//define the GUI for the App
void createTympanRemoteLayout(void) {
  
  // Create some temporary variables
  TR_Page *page_h;  //dummy handle for a page
  TR_Card *card_h;  //dummy handle for a card

  //Add first page to GUI
  page_h = myGUI.addPage("Basic Gain Demo");
      //Add a card under the first page
      card_h = page_h->addCard("Change Loudness");
          //Add a "-" digital gain button with the Label("-"); Command("K"); Internal ID ("minusButton"); and width (4)
          card_h->addButton("-","K","minusButton",4);  //displayed string, command, button ID, button width (out of 12)

          //Add an indicator that's a button with no command:  Label (value of the digital gain); Command (""); Internal ID ("gain indicator"); width (4).
          card_h->addButton("","","gainIndicator",4);  //displayed string (blank for now), command (blank), button ID, button width (out of 12)
  
          //Add a "+" digital gain button with the Label("+"); Command("K"); Internal ID ("minusButton"); and width (4)
          card_h->addButton("+","k","plusButton",4);   //displayed string, command, button ID, button width (out of 12)
        
  //add some pre-defined pages to the GUI
  myGUI.addPredefinedPage("serialMonitor");
  //myGUI.addPredefinedPage("serialPlotter");
}

Next, you need to send this information from the Tympan to the App. See how it's done in the BasicGain_wApp example:

// Print the layout for the Tympan Remote app, in a JSON-ish string
// (single quotes are used here, whereas JSON spec requires double quotes.  The app converts ' to " before parsing the JSON string).
// Please don't put commas or colons in your ID strings!
void printTympanRemoteLayout(void) {
  if (myGUI.get_nPages() < 1) createTympanRemoteLayout();  //create the GUI, if it hasn't already been created
  Serial.println(myGUI.asString());
  ble.sendMessage(myGUI.asString());
  setButtonText("gainIndicator", String(digital_gain_dB));
}

Finally, you need a way for the Tympan to respond to the commands sent by the App. This is accomplished with a switchyard:

//respond to serial commands
void respondToByte(char c) {
  Serial.print("Received character "); Serial.println(c);
  
  switch (c) {
    case 'J': case 'j':
      printTympanRemoteLayout();
      break;
    case 'k':
      changeGain(3.0);
      printGainLevels();
      setButtonText("gainIndicator", String(digital_gain_dB));
      break;
    case 'K':
      changeGain(-3.0);
      printGainLevels();
      setButtonText("gainIndicator", String(digital_gain_dB));
      break;
  }
}

To add more than one page to your GUI or to add more than one card to a page, see the TrebleBoost_wApp example sketch. The TrebleBoost_wApp GUI looks like:

To add built-in GUI elements, like for the compression algorithm (WDRC), check out the TrebleBoost_wComp_wApp example sketch. The built-in WDRC GUI looks like:

This is the GUI that controls the Left Compressor. You would also add a built-in page for the right compressor. The GUI contains additional controls for setting the Compressor Knee, Compressor Ratio, and Limitter Knee (cut off in image).

Creating a GUI Using Dated Methods (Obsolete)

The information below illustrates the old way of creating a GUI in the TympanRemote App. This method is still valid, it's just more complicated having to deal with a JSON-ish string.

User-Defined Pages

The primary way to generate your own buttons and text on the mobile device is to create user-defined pages. You can create as many or as few pages as you would like. Each page can have groups of text or buttons. Within each group are the individual text or buttons. Once the buttons are defined by your program running on the Tympan, the buttons can send commands back to the Tympan. Furthermore, even after you've created the buttons and text elements, your program on the Tympan can also update the state of the buttons and text elements.

When the TympanRemote App first connects over Bluetooth to the Tympan, it sends the letter "J" as a command to the Tympan. Upon receiving this "J", our Tympan program should reply with a JSON object that defines the graphical user interface (GUI) that the TympanRemote App should display. Here is an example:

char jsonConfig[] = "JSON={"
    "'pages':["
       "{'title':'Audio Processing','cards':["
        "{'name':'Highpass Cutoff (Hz)','buttons':[{'label': 'Lower', 'width':'4', 'cmd': 'F'},{'label': '', 'width':'4', 'id':'hp_Hz'},{'label': 'Higher', 'width':'4', 'cmd': 'f'}]},"
        "{'name':'Linear Gain (dB)',     'buttons':[{'label': 'Lower', 'cmd' :'A', 'width':'4'},{'label': '', 'width':'4', 'id':'V_linGain'},{'label': 'Higher', 'cmd': 'a', 'width':'4'}]},"
        "{'name':'Compressor Settings','buttons':[{'label':'Screen To the Right'}]}"  //don't have a trailing comma on this last one
      "]},"      
      "{'title':'WDRC Settings','cards':["
        "{'name':'Comp Knee (dB SPL)',    'buttons':[{'label': 'Lower', 'cmd' :'Z', 'width':'4'},{'label': '', 'width':'4', 'id':'V_compKnee'},{'label': 'Higher', 'cmd': 'z', 'width':'4'}]},"
        "{'name':'Compression Ratio',     'buttons':[{'label': 'Lower', 'cmd' :'V', 'width':'4'},{'label': '', 'width':'4', 'id':'V_compRatio'},{'label': 'Higher', 'cmd': 'v', 'width':'4'}]},"
        "{'name':'Limiter Knee (dB SPL)', 'buttons':[{'label': 'Lower', 'cmd' :'L', 'width':'4'},{'label': '', 'width':'4', 'id':'V_limKnee'},{'label': 'Higher', 'cmd': 'l', 'width':'4'}]},"//no trailing comma on last one
        "{'name':'System Settings','buttons':[{'label':'Screen To the Right'}]}"  //don't have a trailing comma on this last one
      "]},"      
      "{'title':'System Settings','cards':["
        "{'name':'Record to SD Card','buttons':[{'label':'Start', 'cmd':'r', 'id':'recordStart'},{'label':'Stop', 'cmd':'s'}]},"
        "{'name':'CPU Reporting',    'buttons':[{'label':'Start', 'cmd':'c', 'id':'cpuStart'}   ,{'label':'Stop', 'cmd':'C'}]}" //don't have a trailing comma on this last one
      "]}"   //don't have a trailing comma on this last one.                         
    "]"
  "}";
  myTympan.println(jsonConfig);

Built-In Pages

The TympanRemote App has a number of pre-defined pages can that can be invoked with a line such as:

"'prescription':{'type':'BoysTown','pages':['serialMonitor','multiband','broadband','afc','plot']}"

as in the full code below:

char jsonConfig[] = "JSON={"
    "'pages':["
       "{'title':'Audio Processing','cards':["
        "{'name':'Highpass Cutoff (Hz)','buttons':[{'label': 'Lower', 'width':'4', 'cmd': 'F'},{'label': '', 'width':'4', 'id':'hp_Hz'},{'label': 'Higher', 'width':'4', 'cmd': 'f'}]},"
        "{'name':'Linear Gain (dB)',     'buttons':[{'label': 'Lower', 'cmd' :'A', 'width':'4'},{'label': '', 'width':'4', 'id':'V_linGain'},{'label': 'Higher', 'cmd': 'a', 'width':'4'}]},"
        "{'name':'Compressor Settings','buttons':[{'label':'Screen To the Right'}]}"  //don't have a trailing comma on this last one
      "]},"      
      "{'title':'WDRC Settings','cards':["
        "{'name':'Comp Knee (dB SPL)',    'buttons':[{'label': 'Lower', 'cmd' :'Z', 'width':'4'},{'label': '', 'width':'4', 'id':'V_compKnee'},{'label': 'Higher', 'cmd': 'z', 'width':'4'}]},"
        "{'name':'Compression Ratio',     'buttons':[{'label': 'Lower', 'cmd' :'V', 'width':'4'},{'label': '', 'width':'4', 'id':'V_compRatio'},{'label': 'Higher', 'cmd': 'v', 'width':'4'}]},"
        "{'name':'Limiter Knee (dB SPL)', 'buttons':[{'label': 'Lower', 'cmd' :'L', 'width':'4'},{'label': '', 'width':'4', 'id':'V_limKnee'},{'label': 'Higher', 'cmd': 'l', 'width':'4'}]},"//no trailing comma on last one
        "{'name':'System Settings','buttons':[{'label':'Screen To the Right'}]}"  //don't have a trailing comma on this last one
      "]},"      
      "{'title':'System Settings','cards':["
        "{'name':'Record to SD Card','buttons':[{'label':'Start', 'cmd':'r', 'id':'recordStart'},{'label':'Stop', 'cmd':'s'}]},"
        "{'name':'CPU Reporting',    'buttons':[{'label':'Start', 'cmd':'c', 'id':'cpuStart'}   ,{'label':'Stop', 'cmd':'C'}]}" //don't have a trailing comma on this last one
      "]}"   //don't have a trailing comma on this last one.                         
    "],"  //added a comma because it is no longer the last item in the JSON
    "'prescription':{'type':'BoysTown','pages':['serialMonitor','multiband','broadband','afc','plot']}" //added this
  "}";
  myTympan.println(jsonConfig);

The different built-in pages that can be invoked are:

  • multiband: Predefined table input and table display for BTNRH multiband WDRC
  • broadband: Predefined table input and table display for BTNRH broadband WDRC
  • afc: Predefined table input and table display for BTNRH adaptive feedback cancellation
  • serialMonitor: Display all text being received by the TympanRemote App
  • serialPlotter: Graphical display for plotting comma-delimited values, like the Arduino IDE's SerialPlotter
    • The TympanRemote App will send a ']' to the Tympan to ask for data to start
    • All data should start with 'P', have comma separated values, and end in a new line (?) character (such as via println())
    • The TympanRemote App will send a '}' to the Tympan to ask for data to stop