The ARSS

Main Page | Download | Code | Examples | Documentation | MFAQ | Roadmap
C:\msys\home\arss\arss.c.html
/* The Analysis & Resynthesis Sound Spectrograph
Copyright (C) 2005-2008 Michel Rouzic

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.*/

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <math.h>
#include <fftw3.h>
#include <float.h>
#include <time.h>
#include <string.h>

#include "util.h"
#include "image_io.h"
#include "sound_io.h"
#include "dsp.h"

char *version = "0.2.3";
char *date = "May 29th, 2008";

#define MSG_NUMBER_EXPECTED "A number is expected after %s\nExiting with error.\n"

void settingsinput(int32_t *bands, int32_t samplecount, int32_t *samplerate, double *basefreq, double maxfreq, double *pixpersec, double *bandsperoctave, int32_t Xsize, int32_t mode)
{
        /* mode :
         * 0 = Analysis mode
         * 1 = Synthesis mode
         */

        int32_t i;
        double gf, f, trash;
        double ma;                     // maximum allowed frequency
        FILE *freqcfg;
        char byte;
        int32_t unset=0, set_min=0, set_max=0, set_bpo=0, set_y=0;                     // count of unset interdependant settings
        int32_t set_pps=0, set_x=0;
        size_t filesize;               // boolean indicating if the configuration file's last expected byte is there (to verify the file's integrity)
        char conf_path[FILENAME_MAX];  // Path to the configuration file (only used on non-Windows platforms)

        #ifdef DEBUG
        printf("settingsinput...\n");
        #endif

        #ifdef WIN32
        freqcfg=fopen("arss.conf", "rb");                                      // open saved settings file
        #else
        sprintf(conf_path, "%s/%s", getenv("HOME"), ".arss.conf");
        freqcfg=fopen(conf_path, "rb");
        #endif

        if (*samplerate==0)                                    // if we're in synthesis mode and that no samplerate has been defined yet
        {
                if (quiet==1)
                {
                        fprintf(stderr, "Please provide a sample rate for your output sound.\nUse --sample-rate (-r).\nExiting with error.\n");
                        exit(EXIT_FAILURE);
                }
                //********Output settings querying********

                printf("Sample rate [44100] : ");                     // Query for a samplerate
                *samplerate=getfloat();
                if (*samplerate==0 || *samplerate<-2147483647)                // The -2147483647 check is used for the sake of compatibility with C90
                        *samplerate = 44100;                         // Default value
                //--------Output settings querying--------
        }

        if (*basefreq!=0)      set_min=1;   // count unset interdependant frequency-domain settings
        if (maxfreq!=0)                set_max=1;
        if (*bandsperoctave!=0)        set_bpo=1;
        if (*bands!=0)         set_y=1;
        unset = set_min + set_max + set_bpo + set_y;

        if (unset==4)                          // if too many settings are set
        {
                if (mode==0)
                        fprintf(stderr, "You have set one parameter too many.\nUnset either --min-freq (-min), --max-freq (-max), --bpo (-b)\nExiting with error.\n");
                if (mode==1)
                        fprintf(stderr, "You have set one parameter too many.\nUnset either --min-freq (-min), --max-freq (-max), --bpo (-b) or --height (-y)\nExiting with error.\n");
                exit(EXIT_FAILURE);
        }

        if (*pixpersec!=0)     set_pps=1;
        if (Xsize!=0)          set_x=1;

        if (set_x+set_pps==2 && mode==0)
        {
                fprintf(stderr, "You cannot define both the image width and the horizontal resolution.\nUnset either --pps (-p) or --width (-x)\nExiting with error.\n");
                exit(EXIT_FAILURE);
        }

        if (freqcfg)                                                           // load settings from file if it exists
        {
                for (i=0; i<(int32_t) (4*sizeof(double)); i++)
                        filesize=fread(&byte, sizeof(char), 1, freqcfg);     // verify the file's length
                rewind(freqcfg);
        }
        if (filesize==1)                                                       // if the file is at least as long as expected
        {
                if (*basefreq==0)     fread(basefreq, sizeof(double), 1, freqcfg);                // load values from it if they haven't been set yet
                else                  fread(&trash, sizeof(double), 1, freqcfg);
                if (maxfreq==0)               fread(&maxfreq, sizeof(double), 1, freqcfg);         // unless we have enough of them (unset==3)
                else                  fread(&trash, sizeof(double), 1, freqcfg);
                if (*bandsperoctave==0)       fread(bandsperoctave, sizeof(double), 1, freqcfg);
                else                  fread(&trash, sizeof(double), 1, freqcfg);
                if (*pixpersec==0)    fread(pixpersec, sizeof(double), 1, freqcfg);
                else                  fread(&trash, sizeof(double), 1, freqcfg);
        }
        else
        {
                if (*basefreq==0)     *basefreq=27.5;                             // otherwise load default values
                if (maxfreq==0)               maxfreq=20000;
                if (*bandsperoctave==0)       *bandsperoctave=12;
                if (*pixpersec==0)    *pixpersec=150;
        }
        if (freqcfg)
                fclose(freqcfg);

        if (unset<3 && set_min==0)
        {
                if (quiet==1)
                {
                        fprintf(stderr, "Please define a minimum frequency.\nUse --min-freq (-min).\nExiting with error.\n");
                        exit(EXIT_FAILURE);
                }
                printf("Min. frequency (Hz) [%.3f]: ", *basefreq);
                gf=getfloat();
                if (gf != 0)
                        *basefreq=gf;
                unset++;
                set_min=1;
        }
        *basefreq /= *samplerate;       // turn basefreq from Hz to fractions of samplerate

        if (unset<3 && set_bpo==0)
        {
                if (quiet==1)
                {
                        fprintf(stderr, "Please define a bands per octave setting.\nUse --bpo (-b).\nExiting with error.\n");
                        exit(EXIT_FAILURE);
                }
                printf("Bands per octave [%.3f]: ", *bandsperoctave);
                gf=getfloat();
                if (gf != 0)
                        *bandsperoctave=gf;
                unset++;
                set_bpo=1;
        }

        if (unset<3 && set_max==0)
        {
                i=0;
                do
                {
                        i++;
                        f=*basefreq * pow(LOGBASE, (i / *bandsperoctave));
                }
                while (f<0.5);

                ma=*basefreq * pow(LOGBASE, ((i-2) / *bandsperoctave)) * *samplerate; // max allowed frequency


                if (maxfreq > ma)
                        if (fmod(ma, 1.0) == 0.0)
                                maxfreq = ma;                   // replaces the "Upper frequency limit above Nyquist frequency" warning
                        else
                                maxfreq = ma - fmod(ma, 1.0);

                if (mode==0)                                  // if we're in Analysis mode
                {
                        if (quiet==1)
                        {
                                fprintf(stderr, "Please define a maximum frequency.\nUse --max-freq (-max).\nExiting with error.\n");
                                exit(EXIT_FAILURE);
                        }
                        printf("Max. frequency (Hz) (up to %.3f) [%.3f]: ", ma, maxfreq);
                        gf=getfloat();
                        if (gf != 0)
                                maxfreq=gf;

                        if (maxfreq > ma)
                                if (fmod(ma, 1.0) == 0.0)
                                        maxfreq = ma;           // replaces the "Upper frequency limit above Nyquist frequency" warning
                                else
                                        maxfreq = ma - fmod(ma, 1.0);
                }

                unset++;
                set_max=1;
        }

        if (set_min==0)
        {
                *basefreq = pow(LOGBASE, (*bands-1) / *bandsperoctave) * maxfreq;             // calculate the lower frequency in Hz
                printf("Min. frequency : %.3f Hz\n", *basefreq);
                *basefreq /= *samplerate;
        }

        if (set_max==0)
        {
                maxfreq = pow(LOGBASE, (*bands-1) / *bandsperoctave) * (*basefreq * *samplerate);     // calculate the upper frequency in Hz
                printf("Max. frequency : %.3f Hz\n", maxfreq);
        }

        if (set_y==0)
        {
                *bands = 1 + roundoff(*bandsperoctave * (log_b(maxfreq) - log_b(*basefreq * *samplerate)));
                printf("Bands : %d\n", *bands);
        }

        if (set_bpo==0)
        {
                if (LOGBASE==1.0)
                        *bandsperoctave = maxfreq / *samplerate;
                else
                        *bandsperoctave = (*bands-1) / (log_b(maxfreq) - log_b(*basefreq * *samplerate));
                printf("Bands per octave : %.3f\n", *bandsperoctave);
        }

        if (set_x==1 && mode==0)       // If we're in Analysis mode and that X is set (by the user)
        {
                *pixpersec = (double) Xsize * (double) *samplerate / (double) samplecount;    // calculate pixpersec
                printf("Pixels per second : %.3f\n", *pixpersec);
        }

        if ((mode==0 && set_x==0 && set_pps==0) || (mode==1 && set_pps==0))    // If in Analysis mode none are set or pixpersec isn't set in Synthesis mode
        {
                if (quiet==1)
                {
                        fprintf(stderr, "Please define a pixels per second setting.\nUse --pps (-p).\nExiting with error.\n");
                        exit(EXIT_FAILURE);
                }
                printf("Pixels per second [%.3f]: ", *pixpersec);
                gf=getfloat();
                if (gf != 0)
                        *pixpersec=gf;
        }

        *basefreq *= *samplerate;               // turn back to Hz just for the sake of writing to the file

        #ifdef WIN32
        freqcfg=fopen("arss.conf", "wb");      // saving settings to a file
        #else
        freqcfg=fopen(conf_path, "wb");                // saving settings to a file
        #endif
        if (freqcfg==NULL)
        {
                fprintf(stderr, "Cannot write to configuration file");
                exit(EXIT_FAILURE);
        }
        fwrite(basefreq, sizeof(double), 1, freqcfg);
        fwrite(&maxfreq, sizeof(double), 1, freqcfg);
        fwrite(bandsperoctave, sizeof(double), 1, freqcfg);
        fwrite(pixpersec, sizeof(double), 1, freqcfg);
        fclose(freqcfg);

        *basefreq /= *samplerate;       // basefreq is now in fraction of the sampling rate instead of Hz
        *pixpersec /= *samplerate;      // pixpersec is now in fraction of the sampling rate instead of Hz
}

void print_help()
{
        printf(
                "Usage: arss [options] input_file output_file [options]. Example:\n"
                "\n"
                "arss -q in.bmp out.wav --noise --min-freq 55 -max 16000 --pps 100 -r 44100 -f 16\n"
                "\n"
                "--help, -h, /?                Display this help\n"
                "--adv-help                    Display more advanced options\n"
                "--version, -v                 Display the version of this program\n"
                "--quiet, -q                   No-prompt mode. Useful for scripting\n"
                "--analysis, -a                Analysis mode. Not req. if input file is a .wav\n"
                "--sine, -s                    Sine synthesis mode\n"
                "--noise, -n                   Noise synthesis mode\n"
                "--min-freq, -min [real]       Minimum frequency in Hertz\n"
                "--max-freq, -max [real]       Maximum frequency in Hertz\n"
                "--bpo, -b [real]              Frequency resolution in Bands Per Octave\n"
                "--pps, -p [real]              Time resolution in Pixels Per Second\n"
                "--height, -y [integer]        Specifies the desired height of the spectrogram\n"
                "--width, -x [integer]         Specifies the desired width of the spectrogram\n"
                "--sample-rate, -r [integer]   Sample rate of the output sound\n"
                "--brightness, -g [real]       Almost like gamma : f(x) = x^1/brightness\n"
                "--format-param, -f [integer]  Output format option. This is bit-depth for WAV files (8/16/32, default: 32). No option for BMP files.\n"
                );
}

void print_adv_help()
{
        printf(
                "More advanced options :\n"
                "\n"
                "--log-base [real]          Frequency scale's logarithmic base (default: 2)\n"
                "--linear, -l               Linear frequency scale. Same as --log-base 1\n"
                "--loop-size [real]         Noise look-up table size in seconds (default: 10)\n"
                "--bmsq-lut-size [integer]  Blackman Square kernel LUT size (default: 16000)\n"
                "--pi [real]                pi (default: 3.1415926535897932)\n"
              );
}

int main(int argc, char *argv[])
{
        FILE *fin;
        FILE *fout;
        int32_t  i;
        double **sound, **image, basefreq=0, maxfreq=0, pixpersec=0, bpo=0, brightness=1;
        int32_t channels, samplecount=0, samplerate=0, Xsize=0, Ysize=0, format_param=0;
        int32_t clockb;
        char mode=0, *in_name=NULL, *out_name=NULL;

        // initialisation of global using defaults defined in dsp.h
        pi=PI_D;
        LOGBASE=LOGBASE_D;
        LOOP_SIZE_SEC=LOOP_SIZE_SEC_D;
        BMSQ_LUT_SIZE=BMSQ_LUT_SIZE_D;
        #ifdef QUIET
        quiet=1;
        #else
        quiet=0;
        #endif

        printf("The Analysis & Resynthesis Sound Spectrograph %s\n", version);

        srand(time(NULL));

        for (i=1; i<argc; i++)
        {
                if (strcmp(argv[i], "/?")==0) // DOS friendly help
                {
                        argv[i][0] = '-';
                        argv[i][1] = 'h';
                }

                if (argv[i][0] != '-')                                // if the argument is not a function
                {
                        if (in_name==NULL)                   // if the input file name hasn't been filled in yet
                                in_name = argv[i];
                        else
                                if (out_name==NULL)         // if the input name has been filled but not the output name yet
                                        out_name = argv[i];
                                else                                // if both names have already been filled in
                                {
                                        fprintf(stderr, "You can only have two file names as parameters.\nRemove parameter \"%s\".\nExiting with error.\n", argv[i]);
                                        exit(EXIT_FAILURE);
                                }
                }
                else                                          // if the argument is a parameter
                {
                        if (strcmp(argv[i], "--analysis")==0 || strcmp(argv[i], "-a")==0)
                                mode=1;

                        if (strcmp(argv[i], "--sine")==0     || strcmp(argv[i], "-s")==0)
                                mode=2;

                        if (strcmp(argv[i], "--noise")==0    || strcmp(argv[i], "-n")==0)
                                mode=3;

                        if (strcmp(argv[i], "--quiet")==0    || strcmp(argv[i], "-q")==0)
                                quiet=1;

                        if (strcmp(argv[i], "--linear")==0   || strcmp(argv[i], "-l")==0)
                                LOGBASE=1.0;

                        if (strcmp(argv[i], "--sample-rate")==0      || strcmp(argv[i], "-r")==0)
                                if (str_isnumber(argv[++i]))
                                                samplerate = atoi(argv[i]);
                                else
                                {
                                        fprintf(stderr, MSG_NUMBER_EXPECTED, argv[i-1]);
                                        exit(EXIT_FAILURE);
                                }

                        if (strcmp(argv[i], "--min-freq")==0 || strcmp(argv[i], "-min")==0)
                                if (str_isnumber(argv[++i]))
                                {
                                        basefreq = atof(argv[i]);
                                        if (basefreq==0)
                                                        basefreq = DBL_MIN;      // Set it to this extremely close-to-zero number so that it's considered set
                                }
                                else
                                {
                                        fprintf(stderr, MSG_NUMBER_EXPECTED, argv[i-1]);
                                        exit(EXIT_FAILURE);
                                }

                        if (strcmp(argv[i], "--max-freq")==0 || strcmp(argv[i], "-max")==0)
                                if (str_isnumber(argv[++i]))
                                                maxfreq = atof(argv[i]);
                                else
                                {
                                        fprintf(stderr, MSG_NUMBER_EXPECTED, argv[i-1]);
                                        exit(EXIT_FAILURE);
                                }

                        if (strcmp(argv[i], "--bpo")==0              || strcmp(argv[i], "-b")==0)
                                if (str_isnumber(argv[++i]))
                                                bpo = atof(argv[i]);
                                else
                                {
                                        fprintf(stderr, MSG_NUMBER_EXPECTED, argv[i-1]);
                                        exit(EXIT_FAILURE);
                                }

                        if (strcmp(argv[i], "--pps")==0              || strcmp(argv[i], "-p")==0)
                                if (str_isnumber(argv[++i]))
                                                pixpersec = atof(argv[i]);
                                else
                                {
                                        fprintf(stderr, MSG_NUMBER_EXPECTED, argv[i-1]);
                                        exit(EXIT_FAILURE);
                                }

                        if (strcmp(argv[i], "--height")==0   || strcmp(argv[i], "-y")==0)
                                if (str_isnumber(argv[++i]))
                                                Ysize = atoi(argv[i]);
                                else
                                {
                                        fprintf(stderr, MSG_NUMBER_EXPECTED, argv[i-1]);
                                        exit(EXIT_FAILURE);
                                }

                        if (strcmp(argv[i], "--width")==0    || strcmp(argv[i], "-x")==0)
                                if (str_isnumber(argv[++i]))
                                                Xsize = atoi(argv[i]);
                                else
                                {
                                        fprintf(stderr, MSG_NUMBER_EXPECTED, argv[i-1]);
                                        exit(EXIT_FAILURE);
                                }

                        if (strcmp(argv[i], "--loop-size")==0)
                                if (str_isnumber(argv[++i]))
                                                LOOP_SIZE_SEC = atoi(argv[i]);
                                else
                                {
                                        fprintf(stderr, MSG_NUMBER_EXPECTED, argv[i-1]);
                                        exit(EXIT_FAILURE);
                                }

                        if (strcmp(argv[i], "--log-base")==0)
                                if (str_isnumber(argv[++i]))
                                                LOGBASE = atof(argv[i]);
                                else
                                {
                                        fprintf(stderr, MSG_NUMBER_EXPECTED, argv[i-1]);
                                        exit(EXIT_FAILURE);
                                }

                        if (strcmp(argv[i], "--bmsq-lut-size")==0)
                                if (str_isnumber(argv[++i]))
                                                BMSQ_LUT_SIZE = atoi(argv[i]);
                                else
                                {
                                        fprintf(stderr, MSG_NUMBER_EXPECTED, argv[i-1]);
                                        exit(EXIT_FAILURE);
                                }

                        if (strcmp(argv[i], "--pi")==0)                                      // lol
                                if (str_isnumber(argv[++i]))
                                                pi = atof(argv[i]);
                                else
                                {
                                        fprintf(stderr, MSG_NUMBER_EXPECTED, argv[i-1]);
                                        exit(EXIT_FAILURE);
                                }

                        if (strcmp(argv[i], "--format-param")==0     || strcmp(argv[i], "-f")==0)
                                if (str_isnumber(argv[++i]))
                                                format_param = atoi(argv[i]);
                                else
                                {
                                        fprintf(stderr, MSG_NUMBER_EXPECTED, argv[i-1]);
                                        exit(EXIT_FAILURE);
                                }

                        if (strcmp(argv[i], "--brightness")==0       || strcmp(argv[i], "-g")==0)
                                if (str_isnumber(argv[++i]))
                                                brightness = atof(argv[i]);
                                else
                                {
                                        fprintf(stderr, MSG_NUMBER_EXPECTED, argv[i-1]);
                                        exit(EXIT_FAILURE);
                                }

                        // TODO implement --duration, -d

                        if (strcmp(argv[i], "--version")==0  || strcmp(argv[i], "-v")==0)
                        {
                                printf("Copyright (C) 2005-2008 Michel Rouzic\nProgram last modified by its author on %s\n", date);
                                exit(EXIT_SUCCESS);
                        }

                        if (strcmp(argv[i], "--help")==0     || strcmp(argv[i], "-h")==0)
                        {
                                print_help();
                                exit(EXIT_SUCCESS);
                        }

                        if (strcmp(argv[i], "--adv-help")==0)
                        {
                                print_adv_help();
                                exit(EXIT_SUCCESS);
                        }



                }
        }

        if (in_name!=NULL)                     // if in_name has already been filled in
        {
                fin=fopen(in_name, "rb");     // try to open it

                if (fin==NULL)
                {
                        fprintf(stderr, "The input file %s could not be found\nExiting with error.\n", in_name);
                        exit(EXIT_FAILURE);
                }
                printf("Input file : %s\n", in_name);
        }
        else
        {
                if (quiet==1)
                {
                        fprintf(stderr, "Please specify an input file.\nExiting with error.\n");
                        exit(EXIT_FAILURE);
                }

                printf("Type 'help' to read the manual page\n");

                do
                {
                        printf("Input file : ");
                        in_name=getstring();

                        if (strcmp(in_name, "help")==0)              // if 'help' has been typed
                        {
                                fin=NULL;
                                print_help();                   // print the help
                        }
                        else
                                fin=fopen(in_name, "rb");
                }
                while (fin==NULL);
        }

        if (out_name!=NULL)                    // if out_name has already been filled in
        {
                fout=fopen(out_name, "wb");

                if (fout==NULL)
                {
                        fprintf(stderr, "The output file %s could not be opened.\nPlease make sure it isn't opened by any other program and press Return.\nExiting with error.\n", out_name);
                        exit(EXIT_FAILURE);
                }
                printf("Output file : %s\n", out_name);
        }
        else
        {
                if (quiet==1)
                {
                        fprintf(stderr, "Please specify an output file.\nExiting with error.\n");
                        exit(EXIT_FAILURE);
                }
                printf("Output file : ");
                out_name=getstring();
                fout=fopen(out_name, "wb");

                while (fout==NULL)
                {
                        fprintf(stderr, "The output file %s could not be opened.\nPlease make sure it isn't opened by any other program and press Return.\n", out_name);
                        getchar();
                        fout=fopen(out_name, "wb");
                }
        }

        for (i=0; i<strlen(in_name); i++) if (in_name[i]>='A' && in_name[i]<='Z') in_name[i] -= 'A' - 'a';     // make the string lowercase
        if (mode==0 && strstr(in_name, ".wav")!=NULL && strstr(in_name, ".wav")[4]==0)
                mode=1;       // Automatic switch to the Analysis mode

        if (mode==0)
                do
                {
                        if (quiet==1)
                        {
                                fprintf(stderr, "Please specify an operation mode.\nUse either --analysis (-a), --sine (-s) or --noise (-n).\nExiting with error.\n");
                                exit(EXIT_FAILURE);
                        }
                        printf("Choose the mode (Press 1, 2 or 3) :\n\t1. Analysis\n\t2. Sine synthesis\n\t3. Noise synthesis\n> ");
                        mode=getfloat();
                }
                while (mode!=1 && mode!=2 && mode!=3);


        if (mode==1)
        {
                sound=wav_in(fin, &channels, &samplecount, &samplerate);                                        // Sound input
                #ifdef DEBUG
                printf("samplecount : %i\nchannels : %i\n", samplecount, channels);
                #endif

                settingsinput(&Ysize, samplecount, &samplerate, &basefreq, maxfreq, &pixpersec, &bpo, Xsize, 0);      // User settings input
                image = anal(sound[0], samplecount, samplerate, &Xsize, Ysize, bpo, pixpersec, basefreq);     // Analysis
                if (brightness!=1.0)
                        brightness_control(image, Ysize, Xsize, 1.0/brightness);
                bmp_out(fout, image, Ysize, Xsize);                                                             // Image output
        }
        if (mode==2 || mode==3)
        {
                sound = calloc (1, sizeof(double *));
                image = bmp_in(fin, &Ysize, &Xsize);                                                    // Image input

                if (format_param==0)                          // if the output format parameter is undefined
                        if (quiet==0)                                // if prompting is allowed
                                format_param = wav_out_param();
                        else
                                format_param = 32;          // default is 32

                settingsinput(&Ysize, samplecount, &samplerate, &basefreq, maxfreq, &pixpersec, &bpo, Xsize, 1);      // User settings input

                if (brightness!=1.0) brightness_control(image, Ysize, Xsize, brightness);

                if (mode==2)
                        sound[0] = synt_sine(image, Xsize, Ysize, &samplecount, samplerate, basefreq, pixpersec, bpo);       // Sine synthesis
                else
                        sound[0] = synt_noise(image, Xsize, Ysize, &samplecount, samplerate, basefreq, pixpersec, bpo);      // Noise synthesis

                wav_out(fout, sound, 1, samplecount, samplerate, format_param);
        }

        clockb=gettime();
        printf("Processing time : %.3f s\n", (double) (clockb-clocka)/1000.0);

        win_return();

        return 0;
}


This site is in hiatus. Last updated on February 23rd, 2009
©2007-2009 Michel Rouzic