Blame platform-demos/ca/guitar-tuner.js.page

Packit 1470ea
Packit 1470ea
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="guide" style="task" id="guitar-tuner.js" xml:lang="ca">
Packit 1470ea
  <info>
Packit 1470ea
  <title type="text">Guitar tuner (JavaScript)</title>
Packit 1470ea
    <link type="guide" xref="js#examples"/>
Packit 1470ea
    <revision version="0.1" date="2012-03-09" status="stub"/>
Packit 1470ea
Packit 1470ea
    <credit type="author copyright">
Packit 1470ea
      <name>Susanna Huhtanen</name>
Packit 1470ea
      <email its:translate="no">ihmis.suski@gmail.com</email>
Packit 1470ea
      <years>2012</years>
Packit 1470ea
    </credit>
Packit 1470ea
Packit 1470ea
    <desc>Use GTK+ and GStreamer to build a simple guitar tuner application for GNOME.</desc>
Packit 1470ea
  </info>
Packit 1470ea
Packit 1470ea
  <title>Guitar tuner</title>
Packit 1470ea
Packit 1470ea
    <synopsis>
Packit 1470ea
      

In this tutorial we'll construct a small application, Guitar Tuner, using JavaScript and GTK+ and GStreamer. To do and run all the code examples yourself, you need an editor to write code in, terminal and GNOME 3. or higher installed into your computer.

Packit 1470ea
   <list>
Packit 1470ea
      <item>

<link xref="#gstreamer">GStreamer pipelines</link>

</item>
Packit 1470ea
      <item>

<link xref="#script">Script for running the application</link>

</item>
Packit 1470ea
      <item>

<link xref="#imports">Libraries to import</link>

</item>
Packit 1470ea
      <item>

<link xref="#mainwindow">Creating the main window for the application</link>

</item>
Packit 1470ea
      <item>

<link xref="#buttons">Buttons for the tunes</link>

</item>
Packit 1470ea
      <item>

<link xref="#playSound">Making the sounds with GStreamer</link>

</item>
Packit 1470ea
      <item>

<link xref="#connecting">Connecting buttons to playSound</link>

</item>
Packit 1470ea
      <item>

<link xref="#guitarjs">The whole program</link>

</item>
Packit 1470ea
      <item>

<link xref="#terminal">Running the application form Terminal</link>

</item>
Packit 1470ea
    </list>
Packit 1470ea
  </synopsis>
Packit 1470ea
  

After reading this tutorial, you should see this in your screen:

Packit 1470ea
  <media type="image" mime="image/png" src="media/guitar-tuner.png"/>
Packit 1470ea
  <section id="gstreamer">
Packit 1470ea
    <title>GStreamer pipelines</title>
Packit 1470ea
    

GStreamer is GNOME's multimedia framework — you can use it for playing, recording, and processing video, audio, webcam streams and the like. Here, we'll be using it to produce single-frequency tones.

Packit 1470ea
    

Conceptually, GStreamer works as follows: You create a pipeline containing several processing elements going from the source to the sink (output). The source can be an image file, a video, or a music file, for example, and the output could be a widget or the soundcard.

Packit 1470ea
    

Between source and sink, you can apply various filters and converters to handle effects, format conversions and so on. Each element of the pipeline has properties which can be used to change its behaviour.

Packit 1470ea
    <media type="image" mime="image/png" src="media/guitar-tuner-pipeline.png">
Packit 1470ea
      

An example GStreamer pipeline.

Packit 1470ea
    </media>
Packit 1470ea
  </section>
Packit 1470ea
  <section id="script">
Packit 1470ea
    <title>Script for running the application</title>
Packit 1470ea
    
Packit 1470ea
  #!/usr/bin/gjs]]>
Packit 1470ea
    

This line tells how to run the script. It needs to be the first line of the code and it needs to be executable. To get the execution rights go to terminal and run in right folder: chmod +x scriptname. Or you can use the graphical filemanager. Just go to the right folder where your code is, right click you code file, choose properties, click the permissions tab and check the box for allow executing file as a program

Packit 1470ea
    

Packit 1470ea
  </section>
Packit 1470ea
  <section id="imports">
Packit 1470ea
    <title>Libraries to import</title>
Packit 1470ea
    
Packit 1470ea
var Gtk = imports.gi.Gtk;
Packit 1470ea
var Gst = imports.gi.Gst;
Packit 1470ea
Packit 1470ea
const Mainloop = imports.mainloop;]]>
Packit 1470ea
    

In order to have a working program we need to import a few GObject Introspection -libraries to our use. For working UI, we need Gtk and for Gstreamer to work we need Gst. These are imported in the beginning so we have them at use everywhere. Also in the beginning we import a construct Mainloop to handle the timeout to be used with the tuning sounds.

Packit 1470ea
    </section>
Packit 1470ea
  <section id="mainwindow">
Packit 1470ea
    <title>Creating the main window for the application</title>
Packit 1470ea
    
Packit 1470ea
Gtk.init(null, 0);
Packit 1470ea
Gst.init(null, 0);
Packit 1470ea
Packit 1470ea
var guitarwindow = new Gtk.Window({type: Gtk.WindowType.TOPLEVEL, border_width: 100});
Packit 1470ea
guitarwindow.title = "Guitar Tuner";
Packit 1470ea
guitarwindow.connect("destroy", function(){Gtk.main_quit()});
Packit 1470ea
Packit 1470ea
guitarwindow.show();
Packit 1470ea
Gtk.main();]]>
Packit 1470ea
    

Importing Gtk and Gst is not enough, we need to initialize them in order to get them working. When Gtk and Gst are up and running we need to create the window for the application. Later we are going to put all the buttons for making sounds inside this window. In order to get the window showing, we need to tell it to show and we need also to run the code with the Gtk.main()

Packit 1470ea
  </section>
Packit 1470ea
  <section id="buttons">
Packit 1470ea
   <title>Buttons for the tunes</title>
Packit 1470ea
   
Packit 1470ea
var guitar_box = new Gtk.ButtonBox ({orientation: Gtk.Orientation.VERTICAL, spacing: 10});
Packit 1470ea
Packit 1470ea
var E = new Gtk.Button({label: "E"});
Packit 1470ea
var A = new Gtk.Button({label: "A"});
Packit 1470ea
var D = new Gtk.Button({label: "D"});
Packit 1470ea
var G = new Gtk.Button({label: "G"});
Packit 1470ea
var B = new Gtk.Button({label: "B"});
Packit 1470ea
var e = new Gtk.Button({label: "e"});
Packit 1470ea
Packit 1470ea
guitar_box.add(E);
Packit 1470ea
guitar_box.add(A);
Packit 1470ea
guitar_box.add(D);
Packit 1470ea
guitar_box.add(G);
Packit 1470ea
guitar_box.add(B);
Packit 1470ea
guitar_box.add(e);
Packit 1470ea
Packit 1470ea
guitarwindow.add(guitar_box);
Packit 1470ea
Packit 1470ea
guitar_box.show_all();]]>
Packit 1470ea
   

Because Gtk.Window can only contain a single widget, we need to create something under it to be able to add all the necessary buttons inside it. In this example we use Buttonbox. After creating the Buttonbox we create buttons with necessary labels. After we have the buttons we need to add them to the Buttonbox and the Buttonbox must be added to the Gtk.Window and everything in the Buttonbox must be shown.

Packit 1470ea
   

After this stage you should have a window appearing to your screen showing 6 buttons. Right now the buttons don't do anything and we shall address that issue later. Before we can connect the button signals to something we need to code that something first.

Packit 1470ea
  </section>
Packit 1470ea
  <section id="playSound">
Packit 1470ea
   <title>Making the sounds with GStreamer</title>
Packit 1470ea
   
Packit 1470ea
var frequencies = {E: 329.63, A: 440,	D: 587.33,	G: 783.99,	B: 987.77,	e: 1318.5}
Packit 1470ea
Packit 1470ea
function playSound(frequency){
Packit 1470ea
  var pipeline = new Gst.Pipeline({name: "note"});
Packit 1470ea
  var source = Gst.ElementFactory.make("audiotestsrc","source");
Packit 1470ea
  var sink = Gst.ElementFactory.make("autoaudiosink","output");
Packit 1470ea
Packit 1470ea
  source.set_property('freq', frequency);
Packit 1470ea
  pipeline.add(source);
Packit 1470ea
  pipeline.add(sink);
Packit 1470ea
  source.link(sink);
Packit 1470ea
  pipeline.set_state(Gst.State.PLAYING);
Packit 1470ea
Packit 1470ea
  Mainloop.timeout_add(500, function () {
Packit 1470ea
    pipeline.set_state(Gst.State.NULL);
Packit 1470ea
	  return false;
Packit 1470ea
  });
Packit 1470ea
}]]>
Packit 1470ea
   

The first thing we need to do is decide what tunes we want to make when we push a button. The frequencies list takes care of that. After that we get to actually making the sounds with the function playSound. For function playSound we give as an input a frequency (that we just defined in the frequencies variable). First thing we need to construct is a pipeline, a source and a sink. For the source we set the frequency. To the pipeline we add both the source and the sink and then we tell it to keep playing. As a last thing we use the const Mainloop to get the pipeline to stop after a 500ms.

Packit 1470ea
   

Now we have the method of playing a tune when clicking a button. Next well make the connections between pushing a button and playing the correct sound from that button.

Packit 1470ea
  </section>
Packit 1470ea
  <section id="connecting">
Packit 1470ea
   <title>Connecting buttons to playSound</title>
Packit 1470ea
   
Packit 1470ea
E.connect("clicked", function() {
Packit 1470ea
  playSound(frequencies.E);
Packit 1470ea
});
Packit 1470ea
A.connect("clicked", function(){
Packit 1470ea
  playSound(frequencies.A);
Packit 1470ea
});
Packit 1470ea
D.connect("clicked", function(){
Packit 1470ea
  playSound(frequencies.D);
Packit 1470ea
});
Packit 1470ea
G.connect("clicked", function(){
Packit 1470ea
  playSound(frequencies.G);
Packit 1470ea
});
Packit 1470ea
B.connect("clicked", function(){
Packit 1470ea
  playSound(frequencies.B);
Packit 1470ea
});
Packit 1470ea
e.connect("clicked", function(){
Packit 1470ea
  playSound(frequencies.e);
Packit 1470ea
});]]>
Packit 1470ea
   

The method of connecting button clicks to playSound with the correct tune

Packit 1470ea
   is by using the connect method of the button widget. So we choose a button
Packit 1470ea
   to be connected and type E.connect("clicked",
Packit 1470ea
   function(){playSound(frequencies.E);}); The connect
Packit 1470ea
   tells that when pushing E, something should happen. The clicked
Packit 1470ea
   tells the type of the signal happening to E and then in the
Packit 1470ea
   function(){}; we call playSound with the correct note that
Packit 1470ea
   should be associated with the button.

Packit 1470ea
  </section>
Packit 1470ea
  <section id="guitarjs">
Packit 1470ea
    <title>The whole program</title>
Packit 1470ea
    

So this is what all the parts combined looks like. When running this code, you should be able to tune your guitar (if you have correctly calibrated speakers).

Packit 1470ea
      
Packit 1470ea
#!/usr/bin/gjs
Packit 1470ea
var Gtk = imports.gi.Gtk;
Packit 1470ea
var Gst = imports.gi.Gst;
Packit 1470ea
Packit 1470ea
const Mainloop = imports.mainloop;
Packit 1470ea
Packit 1470ea
Gtk.init(null, 0);
Packit 1470ea
Gst.init(null, 0);
Packit 1470ea
Packit 1470ea
var guitarwindow = new Gtk.Window({type: Gtk.WindowType.TOPLEVEL, border_width: 100});
Packit 1470ea
guitarwindow.title = "Guitar Tuner";
Packit 1470ea
guitarwindow.connect("destroy", function(){Gtk.main_quit()});
Packit 1470ea
Packit 1470ea
var guitar_box = new Gtk.ButtonBox ({orientation: Gtk.Orientation.VERTICAL, spacing: 10});
Packit 1470ea
Packit 1470ea
var E = new Gtk.Button({label: "E"});
Packit 1470ea
var A = new Gtk.Button({label: "A"});
Packit 1470ea
var D = new Gtk.Button({label: "D"});
Packit 1470ea
var G = new Gtk.Button({label: "G"});
Packit 1470ea
var B = new Gtk.Button({label: "B"});
Packit 1470ea
var e = new Gtk.Button({label: "e"});
Packit 1470ea
Packit 1470ea
var frequencies = {E: 329.63, A: 440,	D: 587.33,	G: 783.99,	B: 987.77,	e: 1318.5}
Packit 1470ea
Packit 1470ea
Packit 1470ea
function playSound(frequency){
Packit 1470ea
  var pipeline = new Gst.Pipeline({name: "note"});
Packit 1470ea
Packit 1470ea
  var source = Gst.ElementFactory.make("audiotestsrc","source");
Packit 1470ea
  var sink = Gst.ElementFactory.make("autoaudiosink","output");
Packit 1470ea
Packit 1470ea
  source.set_property('freq', frequency);
Packit 1470ea
  pipeline.add(source);
Packit 1470ea
  pipeline.add(sink);
Packit 1470ea
  source.link(sink);
Packit 1470ea
  pipeline.set_state(Gst.State.PLAYING);
Packit 1470ea
Packit 1470ea
  Mainloop.timeout_add(500, function () {
Packit 1470ea
    pipeline.set_state(Gst.State.NULL);
Packit 1470ea
	  return false;
Packit 1470ea
});
Packit 1470ea
}
Packit 1470ea
Packit 1470ea
E.connect("clicked", function() {
Packit 1470ea
  playSound(frequencies.E);
Packit 1470ea
});
Packit 1470ea
A.connect("clicked", function(){
Packit 1470ea
  playSound(frequencies.A);
Packit 1470ea
});
Packit 1470ea
D.connect("clicked", function(){
Packit 1470ea
  playSound(frequencies.D);
Packit 1470ea
});
Packit 1470ea
G.connect("clicked", function(){
Packit 1470ea
  playSound(frequencies.G);
Packit 1470ea
});
Packit 1470ea
B.connect("clicked", function(){
Packit 1470ea
  playSound(frequencies.B);
Packit 1470ea
});
Packit 1470ea
e.connect("clicked", function(){
Packit 1470ea
  playSound(frequencies.e);
Packit 1470ea
});
Packit 1470ea
Packit 1470ea
guitar_box.add(E);
Packit 1470ea
guitar_box.add(A);
Packit 1470ea
guitar_box.add(D);
Packit 1470ea
guitar_box.add(G);
Packit 1470ea
guitar_box.add(B);
Packit 1470ea
guitar_box.add(e);
Packit 1470ea
Packit 1470ea
guitarwindow.add(guitar_box);
Packit 1470ea
Packit 1470ea
guitar_box.show_all();
Packit 1470ea
guitarwindow.show();
Packit 1470ea
Gtk.main();]]>
Packit 1470ea
  </section>
Packit 1470ea
Packit 1470ea
<section id="terminal">
Packit 1470ea
  <title>Running the application form Terminal</title>
Packit 1470ea
  

To run this application open Terminal, go to the folder where your application is stored and then run

<screen> <output style="prompt">$ </output><input> GJS_PATH=`pwd` gjs guitarTuner.js</input> </screen>
Packit 1470ea
    </section>
Packit 1470ea
Packit 1470ea
<section id="impl">
Packit 1470ea
 <title>Implementació de referència</title>
Packit 1470ea
 

If you run into problems with the tutorial, compare your code with this <link href="guitar-tuner/guitar-tuner.js">reference code</link>.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
Packit 1470ea
</page>