domenica 26 novembre 2017

Midi sotto linux


Verificare con il comando:
aconnect -o
di avere in elenco solo "Midi through port": è la modalità di default che invia i comandi midi ad un dispositivo esterno (che ovviamente non abbiamo).

Abbiamo bisogno di un sintetizzatore software come Timidity o FluidSynth, con i loro campioni digitalizzati.

Ho installato quest ultimo con il comando:
 apt-get install fluidsynth fluid-soundfont-gm
ho scaricato un midi di prova da qui.

Ho verificato l'installazione con il comando
fluidsynth --audio-driver=alsa -o audio.alsa.device=hw:0 /usr/share/sounds/sf2/FluidR3_GM.sf2 test1.mid
Se si lancia il sintetizzatore software così:
fluidsynth -l -s -i -aalsa -o audio.alsa.device=default /usr/share/sounds/sf2/FluidR3_GM.sf2
poi il comando iniziale di aconnect mostra anche il driver fluid synth.

Tutto è partito dall'installazione di un videogioco sotto wine che non mi riconosceva il dispositivo midi...

Riferimenti qui e qui.

venerdì 14 aprile 2017

Test HTML5 canvas

Qua sopra c'è un canvas interattivo.

giovedì 5 gennaio 2017

Problemi Bluetooth con Qualcomm Atheros QCA9565 / AR9565 Wireless Network Adapter


Qualcosa che non va in questo portatile con linux l'ho trovato anche io: il bluetooth integrato.

Si tratta di un dispositivo dual wireless, che fornisce connettività sia Wifi che Bluetooth. La parte Wifi funziona senza problemi, mentre nel tentativo di connettere un mouse ho scoperto che la parte che si occupa del bluetooth non rileva assolutamente nulla; ho provato anche a far rilevare il cellulare android ma senza successo.

Ho attaccato un dongle Bluetooth qualsiasi ed ha funzionato senza problemi, quindi deduco che è il driver del dispositivo che non è completamente compatibile.

Il comando inxi -N fornisce informazioni riguardo alle schede di rete:
Network:   Card-1: Realtek RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller
           driver: r8169
           Card-2: Qualcomm Atheros QCA9565 / AR9565 Wireless Network Adapter
           driver: ath9k

e risulta che il driver usato è l'ath9k.

Con il comando lsusb -v esce fuori che il dispositivo ha l'ID
Bus 001 Device 004: ID 04ca:3018 Lite-On Technology Corp.

Cercando il codice 04ca:3018 su google in due giorni diversi, sono usciti risultati diversi, poiche nel frattempo qualcuno ha postato una domanda su askubuntu riguardo allo stesso chip, ed un bug report su launchpad, che è stato sistemato nel giro di poche ore! Molto simile a quello che era successo per il touchpad, ad indicare che l'hardware del mio portatile è sufficientemente nuovo da non aver ancora tutti i dispositivi funzionanti OotB.

La patch riportata sul bug report ha risolto il mio problema, anche se un paio di cuffie bluetooth che ho da poco acquistato non funzionano ancora bene per un problema con bluez e pulseaudio che devo ancora risolvere.


Sistemare la posizione della cartella Desktop/Scrivania


Ho notato che ad un certo punto nella mia home dir erano presenti due cartelle, una chiamata Desktop ed una chiamata Scrivania:


Evidentemente qualche programma ha reimpostato la cartella DESKTOP andando in conflitto con la configurazione locale, per cui si è creata questa situazione.

La posizione della cartella Desktop è definita da una specifica chiamata XDG che definisce una serie di percorsi standard all'interno della home dir di ciascun utente. Un buon articolo della documentazione di ArchLinux descrive brevemente di cosa si tratta.

Sono andato a vedere quindi il contenuto del file ~/.config/user-dirs.dirs ed effettivamente la variabile XDG_DESKTOP_DIR puntava a "$HOME/Desktop" piuttosto che a "$HOME/Scrivania"; ho ripristinato la stringa, ed effettivamente rilanciando il gestore file Nemo, l'icona Desktop adesso è rappresentata come una cartella normale:


Per curiosità sono andato a vedere a cosa puntano le altre cartelle, ed ho notato  XDG_TEMPLATES_DIR: c'è un ottima spiegazione del suo uso su askubuntu.

In base a quanto lì descritto, ho creato due file con un nome significativo, con dentro magari del contenuto di partenza, per cui cliccando con il tasto destro in nemo e selezionando la voce Crea Nuovo Documento, escono proprio i nomi che abbiamo inserito poc'anzi:


Il comando per capire dove punta una delle cartelle definite è il seguente:
xdg-user-dir TEMPLATES
Ne approfitto per inserire tutte le cartelle all'interno della cartella Documenti, in modo da avere una cartella home più snella, per cui il file ~/.config/user-dirs.dirs finale è il seguente:
# This file is written by xdg-user-dirs-update
# If you want to change or add directories, just edit the line you're
# interested in. All local changes will be retained on the next run
# Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped
# homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an
# absolute path. No other format is supported.
#
XDG_DESKTOP_DIR="$HOME/Scrivania"
XDG_DOCUMENTS_DIR="$HOME/Documenti"
XDG_DOWNLOAD_DIR="$HOME/Documenti/Scaricati"
XDG_TEMPLATES_DIR="$HOME/Documenti/Modelli"
XDG_PUBLICSHARE_DIR="$HOME/Documenti/Pubblici"
XDG_MUSIC_DIR="$HOME/Documenti/Musica"
XDG_PICTURES_DIR="$HOME/Documenti/Immagini"
XDG_VIDEOS_DIR="$HOME/Documenti/Video"

lunedì 2 gennaio 2017

Primi esperimenti di desklet in Cinnamon


Dopo qualche settimana di smanettamenti (e smadonnamenti!) vari sono riuscito ad ottenere qualche prototipo funzionante di desklet per cinnamon.

La prima cosa che mi viene da dire è che è veramente difficile riuscire a raccapezzarsi tra tutte le librerie usabili, quali sono le funzioni e come si usano!

Questo perchè il linguaggio usato per l'implementazione dei desklet è il JavaScript, mentre la documentazione delle librerie richiamabili è generata dal codice C, con la possibilità di essere richiamate da codice python o altri linguaggi. Come si immagina la situazione è veramente complessa.

La storia è che sono state inventate delle interfacce per chiamare queste librerie scritte in C dal JavaScript (o da altri linguaggi), raccolte sotto il nome di GObject Introspection.

La documentazione di queste librerie segue lo standard C, per cui ad esempio la funzione
ClutterActor *gtk_clutter_embed_get_stage (GtkClutterEmbed *embed);
va invocata in JavaScript come
const GtkClutter = imports.gi.GtkClutter;
this._clutterEmbed = new GtkClutter.Embed();
this._gtkEmbedActor = this._clutterEmbed.get_stage();
per cui la prima parte del nome della funzione gtk_clutter rappresenta la libreria da importare: GtkClutter; mentre l'oggetto GtkClutterEmbed diventa GtkClutter.Embed; e l'ultima parte del nome della funzione rappresenta come va chiamata la funzione (get_stage); tra l'altro in C non ci sono gli oggetti mentre in JavaScript la funzione viene invocata sull'istanza (this._clutterEmbed).


Documentazione


Un ottimo post che spiega una desklet di tipo hello world è disponibile qui.

Una fonte preziosa di informazioni è quella ufficiale di linuxmint (i creatori di Cinnamon).
 
Un'altra ottima fonte di informazioni è il pacchetto devhelp, che contiene offline un sacco di reference utili; si installa con il comando
 sudo apt install devhelp cinnamon-doc

 

Un esempio


Andando al sodo, ecco un codice di esempio che stampa un'immagine:

il file comune metadata.json:
{
 "uuid": "videoDesk@zac",
 "name": "Video Desklet",
 "description": "Show video streams on your desktop",
 "icon": "",
 "prevent-decorations": false,
 "max-instances": "100",
 "dangerous": false
}

il file desklet.js:
const Desklet = imports.ui.desklet;
const St = imports.gi.St;
const Clutter = imports.gi.Clutter;

function VideoDesk(metadata, desklet_id)
{
 this._init(metadata, desklet_id);
}

VideoDesk.prototype =
{
 __proto__: Desklet.Desklet.prototype,

 _init: function(metadata, desklet_id)
 {
  Desklet.Desklet.prototype._init.call(this, metadata, desklet_id);

  this.window = new St.Bin();

  let imgFilename = '/home/zac/Progetti/videoDesk/image.png';
  this._clutterTexture = new Clutter.Texture({keep_aspect_ratio: true});
  this._clutterTexture.set_from_file(imgFilename)

  this._clutterBox = new Clutter.Box();
  this._binLayout = new Clutter.BinLayout();
  this._clutterBox.set_layout_manager(this._binLayout);
  this._clutterBox.set_width(this.metadata["width"]);
  this._clutterBox.add_actor(this._clutterTexture);
  this.window.add_actor(this._clutterBox);

  this.setContent(this.window);
 }
}

function main(metadata, desklet_id)
{
 return new VideoDesk(metadata, desklet_id);
}



Un trucco pratico


Durante l'implementaizone lancio spesso il desklet per verificare che la sintassi dei comandi che sto scrivendo sia corretta. Un'opzione è quella di aggiungere e rimuovere in continuazione il nostro desklet dal desktop. Ma ho trovato molto più comodo e veloce usare il compilatore di JavaScript di Cinnamon (il cjs). Tra l'altro ho impostato l'editor Scite a lanciarlo ogni volta che premo F5 per cui l'esecuzione e visualizzazione degli errori è ancora più veloce.

In scite la configurazione per la compilazione automatica si ottiene aggiungendo al file di configurazione la linea
command.go.*.js=cjs $(FileNameExt)
il codice del file di test (che mostra un filmato):

#!/usr/bin/cjs

const Lang = imports.lang;
const Gtk = imports.gi.Gtk;
const Gst = imports.gi.Gst;
const Clutter = imports.gi.Clutter;
const ClutterGst = imports.gi.ClutterGst;
const GtkClutter = imports.gi.GtkClutter;

ClutterGst.init(null, null);

const Application = new Lang.Class({
 //A Class requires an explicit Name parameter. This is the Class Name.
 Name: 'Application',

 //create the application
 _init: function() {
  this.application = new Gtk.Application();

   //connect to 'activate' and 'startup' signals to handlers.
   this.application.connect('activate', Lang.bind(this, this._onActivate));
   this.application.connect('startup', Lang.bind(this, this._onStartup));
 },

 //create the UI
 _buildUI: function() {
  this._window = new Gtk.ApplicationWindow({ application: this.application, title: "Hello World!" });
  this._window.set_default_size(200, 200);
  this.label = new Gtk.Label({ label: "Hello World" });

  this.player = new ClutterGst.Playback();
  this.player.set_filename("/home/zac/Scrivania/test.mov");

  this._content = new ClutterGst.Aspectratio();
  this._content.set_player(this.player);

  this._clutterBox = new Clutter.Box();
  this._binLayout = new Clutter.BinLayout();
  this._clutterBox.set_layout_manager(this._binLayout);
  this._clutterBox.set_width(300);
  this._clutterBox.set_height(100);
  this._clutterBox.set_content(this._content);

  this._clutterEmbed = new GtkClutter.Embed();
  this._gtkEmbedActor = this._clutterEmbed.get_stage();
  this._gtkEmbedActor.add_actor(this._clutterBox);

  this._window.add(this._clutterEmbed);

  this.player.set_playing(true);
 },

 //handler for 'activate' signal
 _onActivate: function() {
  //show the window and all child widgetsq
  this._window.show_all();
 },

 //handler for 'startup' signal
 _onStartup: function() {
  this._buildUI();
 },

});

//run the application
let app = new Application();
app.application.run(ARGV);

Il prossimo passo è aprire un repository su GitHub dove piazzare il codice dei miei esperimenti, nel frattempo, buona programmazione!