Saturday 12 September 2015

JackD, Audio Applications and Ubuntu 14.04 64 bit

Just re-installed Ubuntu 14.04 (this time, the 64-bit version).
I'd already set up my bluetooth speaker: see this post.
The next step was to setup JackD so that I could perform sound / midi editing.

I started QJackCtl, and in settings, configured it to automatically run jackd, and show itself in the systray.  I got the following error when I tried to start the server:

D-BUS: JACK server could not be started
What I needed to do to get the server going was:

aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: HDMI [HDA Intel HDMI], device 3: HDMI 0 [HDMI 0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: HDMI [HDA Intel HDMI], device 7: HDMI 1 [HDMI 1]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: HDMI [HDA Intel HDMI], device 8: HDMI 2 [HDMI 2]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: PCH [HDA Intel PCH], device 0: ALC887-VD Analog [ALC887-VD Analog]
  Subdevices: 0/1
  Subdevice #0: subdevice #0
Here, the list tells me that my output device (Analog port) is card 1, so I need to set the hardware Interface to hw:1 in settings, not hw:0 as follows:


Now when I start QJackCtl, the JackD server launches automagically.

JackD and Friends

QJackControl and its Connections

All JackD applications communicate, and JackD is the process that allows this to happen. QJackControl is a front end to JackD, and allows you to manage what is connected to what.  In this example, you can see that the audio synthesizer is connected to the system (speakers).  In this setup, rosegarden (the Midi player) is connected to the synthesizer on the Midi tab.


So you can connect pretty much anything to anything.  When you get going with multi-channel applications, you can route different channels in different directions - route some channels through sound effects processors, route some instruments out to external Midi hardware players, - almost everything is possible.

This is a screenshot of rosegarden outputting Midi to qsynth, which is passing its output to ardour, where it is being recorded, and also passing its output to the meterbridge, and to the speakers.




JackD Compatible Software Tools

QSynth - Midi synthesis
QTractor - Midi Playing / Editing
Ardour - Multi-track Editing
MeterBridge -  Audio Level Monitoring

RoseGarden - Midi Editing

Other Tools

RipperX - CD Ripping
Audacity - Tempo Change (Change Tempo without Pitch Change, e.g. -50% doubles the track length)
Brasero - CD Burning







Friday 11 September 2015

QT WebEngineView Communication with Javascript

Introduction

The QT WebEngineView is the new method of providing applications that display, and interact with web pages.

There is some documentation on the QT website on how to implement these functions, with references to the previous QWebView method, but these are lacking examples.

I have produced the following with QT5.5:

Download C++ QT Source for an example, which is a simple QT application with a dialog containing a widget (called HtmlPage).  This widget is based on QWebEngineView, and extends it very slightly to:

  • Initialise the web page, and set up a communications channel to it
  • Provide a function to request the JavaScript web page to  insert a dot at a given X/Y coordinate.
  • Provide a function to receive information regarding a cursor movement and emit a signal to the main window.

Similarly, the example web page has embedded JavaScript to:
  • Initialise and set up a communications channel to the QT application
  • Produce a  dot at a given X/Y coordinate.
  • Emit a signal (function call) to the QT application indicating the cursor has moved.
  • Include a signal handler to place a large dot at the mouse cursor position, and emit a signal when the mouse is clicked.

So the example has two-way communication with the JavaScript inside the web page.
  • When the mouse is clicked (Javascript), the handler places a large dot at the cursor position.
  • The Javascript then informs the QT C++ application with a £widget.functioncall£.
  • Some time later (asynchronously), the C++ application receives the message in the "functioncall" slot.
  • The C++ class emits a signal to the mainwindow to allow the X/Y coordinates to be updated on the screen.
  • The C++ class then makes a call back to the Javascript to place a smaller dot at the same position.
  • Some time later (asynchronously), the Javascript handler receives the message and places the dot.

Hopefully, the code will be somewhat explanatory, but here's a quick overview of the important bits:

C++

Add the "QT += webenginewidgets webchannel" to your project.pro file, and include the appropriate header files, and then in your C++ class / you need to set up the  communications channel.  Note that 'channel' should be declared in the class header.
// Set up the communications channel for this QWebEngineView parented class
this->page()->setWebChannel(&channel) ;
channel.registerObject("widget", this) ;
To call the Javascript, build a javascript function call into a string, and then call the page()->runJavascript() function.
QString command = QString("javascriptFunction(%1);").arg(functionParameter) ;
page()->runJavaScript(command) ;

To receive messages from Javascript, public slots must be used:
public slots:
    void updateComplete(int x) ;

Javascript

To initialise, the following script line should be included:
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
Then the <body> tag should have an onload="initialise()" option.
In the initialise function, the other end of the communications link should be set up, noting that the setting of (in this case) widget is asynchronous to the initialise function call.  Note also that 'widget' should be a global variable.
var widget ;

function initialise() {
  if (typeof qt != 'undefined') new QWebChannel(qt.webChannelTransport, function(channel) {
    widget = channel.objects.widget;
  } );
}
Some time after the initialisation, the widget variable will be defined (it will be of type QObject).  You can emit signals to C++ simply by calling the appropriate function, so for example:
widget.updateComplete(x) ;
Will emit a signal which will be captured some time later in the updateComplete(int x) slot in the C++ class. You need to appreciate that all calls between C++ and Javascript are asynchronous with QtWebEngineView.