venerdì 20 dicembre 2013

LifeGame, il gioco della vita

In realtà erano anni che mi frullava per la testa l'idea di creare una mia versione del gioco della vita, ma per un motivo o per un altro, non l'avevo mai sviluppato.
Però ultimamente sono stato preso dalla documentazione ufficiale del progetto GNOME, e sono venuto a conoscere una libreria di nome clutter la quale viene descritta nel progetto come “una libreria per creare animazioni e interfacce grafiche eleganti”; mi sono così incuriosito e ho dato un'occhiata alla documentazione ufficiale di questa libreria: non mi ci è voluto molto a capire che segue lo stesso stile di GTK+, usa le sue stesse librerie (GObject, GLib, GDK ecc.), è integrata nell'ambiente GNOME e usa le librerie OpenGL.
Così, mani sulla tastiera, ho cominciato a sviluppare con clutter il solitario che ho sviluppato circa due anni fa per windows e creare una versione giocabile, ma il progetto è lungo e continua ancora adesso.
Quindi ho deciso di usare clutter per sviluppare il gioco della vita, che è più veloce e meno impegnativo: 4 giorni e ho implementato la versione 0.8, in cui oltre a usare clutter, mi sono avvalso della libreria clutter-gtk la quale fa da “ponte” per le librerie clutter e gtk.

Più avanti ne approfitterò per avviare un mini-tutorial su clutter descrivendo il codice sorgente del gioco della vita.

Il gioco della vita

Il gioco della vita è un automa cellulare che come il nome stesso dice, simula alcuni comportamenti assimilabili alla vita, alla crescita della popolazione e così via. Personalmente mi piace immaginarlo come popolazioni di umani su una terra che si stanziano (forme stabili) o vagano (forme dinamiche) su un territorio, dove possono entrare in guerra fra loro (collisioni) o convivere pacificamente, oppure ancora dove possono prosperare (automi a crescita infinita), o morire (configurazioni che scompaiono dopo tot-generazioni).
Dopo aver confuso le idee del lettore che non conosce il gioco della vita, passo a spiegare come funziona lo stesso. Esso si basa su uno spazio costituito da celle, dove ogni cella può essere accesa (viva) o spenta (morta). La configurazione in cui si trova lo spazio funziona da input per la generazione seguente, la quale funzionerà da input per la generazione seguente ancora e così via: esso è Turing-compatibile, infatti è possibile configurare le celle in una maniera particolare costruendo porte logiche e implementare istruzioni.
Le regole che determinano il passaggio da una generazione a un'altra sono essenzialmente due:
  1. Se una cella è morta, essa nasce se ha esattamente 3 celle vive accanto
  2. Se una cella è viva, essa muore se ha un numero di celle accanto diverso da 2 o da 3, per isolamento o sovraffollamento
Queste semplici regole permettono di creare un gran numero di configurazioni, elencate qui appresso.
  • Forme stabili:
    • Blocco
    • Barca
  • Oscillatori:
    • Lampeggiatore
    • Rospo
  • Nav icelle:
    • Aliante
    • Astronave
  • Altro:
    • Cannone di alianti
    • Die hard

Il software

Il software che ho sviluppato è minimale, usa clutter ma non usa appieno le sue potenzialità (probabilmente avrei potuto sviluppare il gioco anche col solo uso di gtk).
Si presenta con la barra degli strumenti in alto, lo stage al centro, e la barra di stato in basso per il conteggio delle generazioni:
La scena del gioco con un oscillatore e un aliante

La barra degli strumenti:
La barra degli strumenti

contiene i comandi per:
  • Creare una nuova scena
  • Aprire un file
  • Salvare un file
  • Mettere in pausa/riprendere
  • Le impostazioni
  • Modificare il ritardo (in ms) tra una generazione e un'altra
  • Informazioni sul programma
Il supporto per i file è in realtà un modo per salvare delle configurazioni particolari (per esempio salvare una navicella), ma devo ancora perfezionarlo perché non è molto utile (potrebbe essere utile se riuscissi a importare nella scena il contenuto del file in una determinata posizione della scena stessa).

Installazione

Innanzitutto, per ora è disponibile solo per linux. Purtroppo per varie difficoltà nel compilare i sorgenti di clutter e clutter-gtk su windows, non posso andare avanti (fortunatamente il team gtk+ fornisce già i binari compilati per windows).

È possibile installare il software in due modi:
1)Compilando i sorgenti
2)Installando il pacchetto .deb per i sistemi debian/ubuntu


Per compilare i sorgenti è necessario avere installati sul sistemai seguenti pacchetti:
  • pkg-config
  • libgtk-3-dev
  • libclutter-1.0-dev
  • libclutter-gtk-1.0-dev
    quindi basta scaricare ed estrarre in una cartella il contenuto del file lifegame-0.8-src.tar.gz, aprire il terminale, posizionarsi sulla cartella con i file estratti:
cd [percorso-cartella]
e lanciare il comando:
sudo ./install
il quale lancia il file di script “install” che ho preparato il quale compila i sorgenti e installa il software nel sistema. Per i sistemi che hanno GNOME o simili, come ubuntu, è possibile trovarlo nelle applicazioni sotto la categoria “giochi”, altrimenti è possibile lanciarlo da terminale col comando “lifegame”.

Per installare direttamente i binari è possibile scaricare il comodo pacchetto .dev (per i sistemi con pacchettizzazione debian, come Debian stesso e Ubuntu) che risolve automaticamente le dipendenze. Per installare il pacchetto .deb su ubuntu basta aprirlo con un doppio click oppure digitare da terminale:

dpkg --install lifegame-0.8.deb

Download:

giovedì 12 dicembre 2013

Linux: come riprodurre un'onda sonora tramite l'interfaccia ALSA

Un'onda sinusoidale PCM
Qualche tempo fa (= due anni fa :D) vi ho mostrato come riprodurre un'onda sonora tramite l'interfaccia WaveOut di Windows, oggi vi mostrerò come riprodurre un'onda sonora su Linux tramite l'interfaccia ALSA, la libreria di basso livello divenuta uno standard de facto per il sonoro su Linux, tant'è che oggi viene distribuita col kernel di Linux direttamente.

Cos'è ALSA?

ALSA (Advanced Linux Sound Architecture) è un modulo del kernel di linux, ovvero un programma che estende le funzionalità del kernel. Per la sua vicinanza al kernel, è molto usata dalle applicazioni che vogliono comunicare direttamente con la scheda audio, anche se esistono molte altre comode librerie (PulseAudio, Gstreamer) che si interfacciano a loro volta ad ALSA ma che semplificano di molto la vita ai programmatori.

Prima dell'avvento di ALSA (che supporta anche le periferiche MIDI) esisteva un altro “standard” su linux, OSS (Open Sound System), il quale aveva la particolarità di permettere al programmatore di comunicare direttamente con la scheda audio tramite il device a caratteri (un file che, nei sistemi Unix, comunica coi driver di un qualsiasi dispositivo) /dev/dsp, la sua forza stava nel fatto di scrivere dati su questo file come se fosse un qualunque altro file, e di leggerli: la prima operazione riproduceva un sonoro, la seconda permetteva la registrazione. Oggi OSS non viene più distribuito su Ubuntu e il device a caratteri /dev/dsp non c'è più fisicamente, ma se non sbaglio (devo informarmi di più su questo argomento) ALSA dovrebbe mantenere una retrocompatibilità con OSS.

Setting up ALSA (preparazione)

Per utilizzare ALSA dobbiamo scaricare i file di sviluppo (header e librerie), e quindi dobbiamo installare il pacchetto libasound2-dev scaricando i sorgenti dal sito ufficiale e compilando oppure, più semplicemente, su Debian Ubuntu andare sul terminale e scrivere:
sudo apt-get install libasound2-dev
che farà tutto lui. Per compilare un'applicazione ALSA (tipo quella che verrà trattata in questo post) basta compilare da terminale scrivendo:
gcc esempio.c -o esempio -lasound
quindi lanciare il programma compilato con:
./esempio
Volendo si può compilare anche con pkg-config se l'avete configurato, ma visto che ALSA non vuole linkate molte librerie il suo uso anzi è più complicato che scrivere solamente -lasound.
  • Se avete installato il pacchetto con apt-get (come la riga sopra) allora avrete i file nei posti giusti e il compilatore troverà sia l'header che noi indichiamo nel file .c, che la libreria lasound
  • Se avete compilato e installato manualmente dovrete indicare a gcc sia la cartella dell'header di alsa che la libreria libasound2
A questo punto possiamo passare al codice.

Un po' di codice

Il codice è veramente breve e semplicissimo se avete già letto il vecchio post che spiega come creare l'onda sinusoidale. Creare l'onda è la difficoltà maggiore, perché una volta stabiliti i parametri del file wave, le funzioni di ALSA sono molto intuitive. Riporto per intero il codice:
#include <stdio.h>
#include <alsa/asoundlib.h>


typedef enum {
TIME = 5, // Durata della traccia (secondi)
CHANNELS = 1, // Numero dei canali
SAMPLE_RATE = 44100, // Frequenza di campionamento (Hz)
BITS_PER_SAMPLE = 8, // Bits per campione
BLOCK_ALIGN = CHANNELS * BITS_PER_SAMPLE / 8, // Allineamento del blocco
BYTES_PER_SECOND = SAMPLE_RATE * BLOCK_ALIGN, // Frequenza di campionamento in Hz
SAMPLES = CHANNELS * SAMPLE_RATE * TIME, // Numero di campioni richiesti per la durata scelta
} WAVE;




int main() {
/*
* Creo puntatore con l'onda sinusoidale
*/
char* ptr;
int tone = 440; //440 Hertz
float volume = 10.0f;
float pulsazione = ( 2.0f * 3.14f / (float) SAMPLE_RATE / CHANNELS ) * (float) tone;
int i;
if ((ptr = (char*)malloc(SAMPLES))==NULL){
fprintf (stderr,"Si e' verificato un errore!\n");
return EXIT_FAILURE;
}
for (i=0 ; i < SAMPLES; i++ )
ptr[i] = (char) ( cos( (float) i * pulsazione ) * volume + 128.0f );
/*
* Inzializzo ALSA
*/
snd_pcm_t *handle; //handle del device
int err;
err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC); //apro il device
if (err<0){
fprintf (stderr,"Si e' verificato un errore!\n");
return err;
}
err = snd_pcm_set_params(handle,SND_PCM_FORMAT_U8 ,SND_PCM_ACCESS_RW_INTERLEAVED,CHANNELS,SAMPLE_RATE,0,0);
if (err<0){
fprintf (stderr,"Si e' verificato un errore!\n");
return err;
}
/*
* invio dati
*/
snd_pcm_writei(handle,ptr,SAMPLES);
snd_pcm_close(handle);
}


Con l'istruzione
err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC);
assegniamo apriamo il device sonoro di default, conservando il suo handle in “handle”, specificando che apriamo il device per la riproduzione (SND_PCM_STREAM_PLAYBACK), in maniera asincrona (SND_PCM_ASYNC) anche se non ce ne facciamo niente del fatto che lo apriamo in maniera asincrona perché dovremmo specificare la funzione di callback per ricevere asincronicamente dei segnali (non è argomento di questo post).
Con l'instruzione
err = snd_pcm_set_params(handle,SND_PCM_FORMAT_U8 ,SND_PCM_ACCESS_RW_INTERLEAVED,CHANNELS,SAMPLE_RATE,0,0);
settiamo i parametri necessari per la riproduzione sul device “handle” in particolare gli diciamo che il formato dei samples PCM è unsigned 8 bit (ovvero il char), specificando il modo di accesso (SND_PCM_ACCESS_RW_INTERLEAVED, adatto per quello che dobbiamo fare), il numero di canali, la frequenza di campionamento, se ALSA deve ricampionare i campioni (0 per NO, 1 per SI), e la latenza della scheda audio, che supponiamo in questa sede che sia nulla.
Per l'invio dei campioni al device usiamo:
snd_pcm_writei(handle,ptr,SAMPLES);
dove specifichiamo il device (handle), il puntatore ai campioni (ptr) e il numero di sample da inviare (SAMPLES).


Rimando a un'altra volta (magari fra due anni :P) lo sfruttamento della modalità asincrona.

Fine.

martedì 10 dicembre 2013

I comandi più divertenti di linux

Ci sono alcuni comandi (=programmi) che ho scoperto su linux che non sono altro che comandi creati a scopo goliardico, senza alcuna utilità se non quella di strapparci un piccolo sorriso. Possiamo vederli qui appresso, ordinati iniziando da quelli che considerò più divertenti.

1. sl

Il comando ls su linux ("list) serve per elencare i file contenuti in una cartella, senza opzioni elenca i file contenuti nella cartella corrente. Essendo un comando molto usato, può capitare che nella fretta qualcuno scriva "sl" invece che "ls", causando un simpatico effetto: un treno che passa dalla finestra del terminale. 

Normalmente nelle distro non è installato, ma su Debian/Ubuntu per installarlo basta scrivere sul terminale:
sudo apt-get install sl

2. xcowsay

 Questo comando non fa altro che lanciare una applicazione GTK+ che visualizza una mucca che "dice" quello che noi le passiamo come argomento. 

Per installarla lanciamo:
sudo apt-get install xcowsay

3. figlet & toilet

Due programmi analoghi che stampano usando l'ASCII art quello che noi passiamo come argomento. 

Per installarli:
sudo apt-get install figlet
sudo apt-get install toilet

4. oneko

Per i gattofili c'è una simpatica applicazione che in effetti potete lanciare e lasciarla in background. Mostra un gattino che segue sempre il vostro mouse, (in realtà il puntatore del mouse):
Per installarlo:
sudo apt-get install oneko
Mentre per lanciarlo e lasciarlo in background:
oneko &
Poi premete INVIO e scrivete "exit" per uscire dal terminale senza chiudere l'applicazione.

5. moo

Rimanendo sempre in tema mucca, visto che fa molto simpatia, ecco quest'altra chicca: in realtà è un easter-egg di apt-get, sistema di pacchettizzazione di debian. Basta scrivere:
apt-get moo

6. fortune

Questa è una vecchia applicazione per Unix, quindi presente anche in Linux oggi. Mostra un messaggio pseudo-casuale preso da un database di citazioni. Pesa circa 2 megabyte, per installarlo:
sudo apt-get install fortune