Sax Trainer

De Wikijoan
Dreceres ràpides: navegació, cerca

Contingut


Recuperar el codi que tenia del sax trainer que havia fet amb Visual Basic.

Es tracta de fer un aplicatiu per estudiar saxo (o d'altres instruments solistes). Hi ha un sol executable que fa diferents funcions. Ara be, la gràcia està en dissenyar uns scripts que cridin a l'executable. Cada script és una sessió d'entrenament. Hi haurà scripts de 5 min, 10, 15, etc. Hi ha scripts per estudiar escales, arpegis, notes llargues, afinació,... o tot combinat.

En ppi està pensat per a saxo, pero es pot aplicar a altres instruments (solistes).

Ha de ser JACK compatible. Té les funcions de metrònom, tempo, tocar prèviament el que he de fer, una vegada o N loops,...

Un controlador midi que s'acciona amb el peu pot ajudar a canviar la comanda, variar el tempo,...

També és interessant portar un registre del que es va fent, gravant-ho a un fitxer de text o a una BD. A posteriori es poden obtenir estadístiques.

La idea és que l'aplicacio funciona en mode text, a posteriori es poden afegir front-ends. Concretament, interessa un front-end basat en OpenGL i SSL, a pantalla completa i format gran.

Buscar un bon mètode de pràctica del saxo: notes llargues, dinàmiques, artculació, notes creixents i decreixents,...

Arguments de la línia de comandes:

-Instrument: per saber el rang i la transposicio
-mode1: escala, arpegi, afinacio, notes llargues
-mode2: una escala, tot el rang
-mode3: articulació
-mode4: dinàmiques
-tempo
-durada
-so previ
-metrònom
-verbose
-registre a bd (fitxer de configuració)
-ensenya estadístiques
- ...

scripts:


Referències a Internet

Exercicis de long tones, warm up's, scales i routines

videos:

Programació de l'API de JACK per enviar missatges MIDI

midiseq.c seria el HelloWorld d'enviar un missatge midi, i és el que he de provar.

midiseq.c: funciona perfectament

$ gcc -std=c99 -o jack_midiseq `pkg-config --cflags --libs jack` midiseq.c

(l'opció -std=c99 no cal, mirar per què serveix)

$ jack_midiseq

usage: jack_midiseq name nsamp [startindex note nsamp] ...... [startindex note nsamp]
eg: jack_midiseq Sequencer 24000 0 60 8000 12000 63 8000
will play a 1/2 sec loop (if srate is 48khz) with a c4 note at the start of the loop
that lasts for 12000 samples, then a d4# that starts at 1/4 sec that lasts for 800 samples
<pre>
per ex,
<pre>
$ jack_midiseq Sequencer 44100 0 60 44100 0 64 44100 

toca l'acord Do4-Mi4 amb loops de 1 segon. He ficat 44100 perquè amb aquest samplerate és com he arrencat el JACK (si no l'arrenco jo, l'arrenca el programa amb la configuració per defecte).

Per fer-ho funcionar he d'arrencar el fluidsynth amb l'opció -m jack (apareix el fluidsynth en la pestanya MIDI del JACK):

$ /usr/bin/fluidsynth -a jack -m jack /home/joan/soundfonts/YAMAHADX7Piano.SF2

i he de connectar la meva aplicació (Sequencer en l'exemple) amb el fluidsynth (en la pestanya MIDI), i en la pestanya AUDIO el fluidsynth amb system.

A partir d'aquí ja tinc un codi que funciona i que el puc adaptar a la meva aplicació sax_trainer.

modifico midiseq-c a midiseq2.c per tal de tocar una sola nota que es va repetint i simplificar el codi.

Aprofundint en l'API de JACK

La mare dels ous està en la funció jack_set_process_callback. Trobo informació i exemple de codi de diferents llocs.

The process callback for this JACK application. It is called by JACK at the appropriate times.

...
int process (jack_nframes_t nframes, void *arg)
{
...
}

...

/* tell the JACK server to call `process()' whenever there is work to be done. */
jack_set_process_callback (client, process, 0);
...

The important bit:

int process (jack_nframes_t nframes, void *arg)
{
    jack_default_audio_sample_t *out =
                (jack_default_audio_sample_t *)
                jack_port_get_buffer (output_port, nframes);
    jack_default_audio_sample_t *in =
                (jack_default_audio_sample_t *)
                jack_port_get_buffer (input_port, nframes);

    memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes);
   
    return 0;     
}

Now, this really is the important bit. This function gets called by JACK when there is processing to be done. It must have an return type of int, and take the parameters shown (jack_nframes_t nframes, void *arg), although the name is up to us. We'll see how we inform JACK that this is the function we want it to use later on, but for now lets have a look at what it does.

From a high-level perspective, this function reads the available data from its input port and copies it to its output port. That's all.

...

main needs to create ports and a jack client, connect the ports to other ports and pass our callbacks to JACK

How it does this is more interesting. We are given nframes as a parameter, and this is the number of frames available on all of our input ports, and the number of frames we are expected to write to our output ports. jack_default_audio_sample_t is used to hold audio data, and we declare two pointers of this type, in and out - one point to available input and the other to point to our output buffer. The buffers are then retrieved using jack_port_get_buffer, which returns a pointer to the buffer associated with the given port, of the given length. The bit in the middle of the first two lines just casts the returned pointer into a pointer to data of type jack_default_audio_sample_t.

memcpy is then used to copy the available data - length calculated using sizeof (jack_default_audio_sample_t) * nframes) from the input to the output.

And then we return. Simple.

You might be wondering what the parameters are. I'll tell you: nframes is the number of frames that need dealing with. That's simple enough, but what about the pointer called arg? This is a little more complicated - the documentation is a little vague on this point, but it appears that this is there so that we can pass our own arguments to the method. Don't worry about this yet, though. We'll deal with it properly later.

    /* tell the JACK server to call `process()' whenever
       there is work to be done.*/

    jack_set_process_callback (client, process, 0);

So, now we have a single cycle of sound, we need to send that to our output port repeated over and over. And remember that we can't just start at 0 every time!

The easiest way I could think of doing this was to store the current position in the cycle. Then, we copy the cycle sample by sample into the buffer of the output port, starting at the offset and adding one to it each time. When the offset reaches the end of the cycle, we just set it back to 0. This way, if the number of samples to be output is not a whole multiple of the number of samples in the cycle, we can still be sure that the wave will carry on correctly.

main.c

Les primeres línies de codi serien una cosa així:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int x=0;
    char ak[2];
    char pb[] = "C  D# Eb F  G  A  B  C  ";

    system("clear");
    printf("Les notes a tocar són:\n");

    do
    {
        printf("%c%c ",pb[x],pb[x+1]);
        fflush(stdout);
        sleep(1);
        x=x+3;
    }
    while( pb[x]!='\0' );

    printf("\n\nPress Enter to exit.");
    getchar();
   
    system("cls");
    system("clear");
   
    return (0);
}

compilació condicional

La meva aplicació té dues funcionalitat extres:

Ara bé, també hi ha l'opció de què la gent que no tingui instal.lada aquestes llibreries ho pugui utilitzar en el mode bàsic de consola. Com es fa? Doncs mitjançant la precompilació definida. El que explico ara funciona tant en gcc com en g++, en C normal com en C++.

main.c o main.cpp

//si tinc instal.lada la llibreria jack.h i vull utilitzar la futura opció -j (per tal que l'aplicació sigui un client de JACK):
//gcc -Djack -o main main.c
//g++ -Djack -o main main.cpp
//això és una macro: compilació condicional

#include <stdio.h>
#include <stdlib.h>

#ifdef jack
#include <jack.h>
#endif

int main()
{
	printf("és un exemple de compilació condicional\n");
	return (0);
}

Si no tinc la llibreria jack.h:

$ gcc -Djack -o main main.c
o
$ g++ -Djack -o main main.cpp
main.cpp:9:18: error: jack.h: No existe el fichero ó directorio

si tinc la llibreria jack.h compila bé, però si no la tinc em dóna l'error anterior. I com que no vull fer servir la llibreria jack.h ho compilo de la forma senzilla:

$ gcc -o main main.c
o
$ g++ -o main main.cpp

A dins del codi, tota la referència a les funcions de la llibreria jack.h no he de permetre que s'executin

sax_trainer i Phasex: alsa/jack midi bridge

Ja puc utilitzar sax_trainer amb el Phasex (soft synth). Està explicat a

Eel problema era que sax_trainer és un client de JACK midi (apareix a la pestanya MIDI amb un port de sortida), i Phasex només té un port d'entrada a la pestanya ALSA. S'ha de fer un pont. Hi ha vàries solucions: utilitzar a2jmidid; utilitzar a2jmidi_bridge; obrir jackd amb l'opció -Xseq; obrir jackd amb l'opció -Xraw.


creat per Joan Quintana Compte, agost 2010-setembre 2010

Eines de l'usuari
Espais de noms
Variants
Accions
Navegació
Institut Jaume Balmes
Màquines recreatives
CNC
Informàtica musical
joanillo.org Planet
Eines