Now using getopt for options parsing
This commit is contained in:
parent
9fa7594b12
commit
7c7941ee4f
21
README.md
21
README.md
@ -1,13 +1,13 @@
|
|||||||
(Bad) Artificial Song Generator
|
(Bad) Artificial Song Generator
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
This is just a simple C code to handle wave files (see files wave_stuf.* for the functions) and a simple application to generating purely artificial sounds (just by creating a wave file with values from a sine wave at the good frequency to make a note.
|
This is just a simple C code to handle wave files (see files wave_stuf.* for the functions) and a simple application to generate purely artificial sounds (just by creating a wave file with values from a sine wave at the good frequency to make a note).
|
||||||
|
|
||||||
### Included files are :
|
### Included files are :
|
||||||
|
|
||||||
* _examples_ folder with some examples music sheets and the resulting generated wave files
|
* _examples_ folder with some examples music sheets and the resulting generated wave files
|
||||||
* _generateur.c_ which is the main program
|
* _generateur.c_ which is the main program
|
||||||
* _generateur_partition.py_ which is just a simple program to generate basic music sheet to use with the main program
|
* _generateur_musicsheet.py_ which is just a simple program to generate basic music sheet to use with the main program
|
||||||
* _wave_stuff.*_ which are the functions to handle wave files
|
* _wave_stuff.*_ which are the functions to handle wave files
|
||||||
|
|
||||||
## Usage of the main program
|
## Usage of the main program
|
||||||
@ -15,12 +15,15 @@ This is just a simple C code to handle wave files (see files wave_stuf.* for the
|
|||||||
The main program should be compiled using the makefile.
|
The main program should be compiled using the makefile.
|
||||||
|
|
||||||
To use it, just run from command line :
|
To use it, just run from command line :
|
||||||
<code>generateur.out partition output.wav bpm silence</code> where
|
<code>./generateur.out options</code> where
|
||||||
|
|
||||||
* _partition_ is the path to the music sheet you want to generate
|
options are amongst :
|
||||||
* _output.wav_ is the resulting wave files
|
|
||||||
* _bpm_ is the speed of the song (in bpm)
|
* _-m_ (or _--musicsheet_) _file_ where _file_ is the path to the music sheet you want to generate. [mandatory argument]
|
||||||
* _silence_ is an integer that should be set to 1 to add silences between notes
|
* _-o_ (or _--output_) _file_ where _file_ is the resulting wave file. [mandatory argument]
|
||||||
|
* _-b_ (or _--bpm_) _bpm_ where _bpm_ is the speed of the song (in bpm). [mandatory argument]
|
||||||
|
* _-s_ (or _--silence_) to add silences between notes. [optional argument]
|
||||||
|
* _-h_ (or _--help_) to display an help message.
|
||||||
|
|
||||||
## Usage of the basic music sheet generator
|
## Usage of the basic music sheet generator
|
||||||
|
|
||||||
@ -29,9 +32,9 @@ This program allows you to write a simple music sheet without always looking for
|
|||||||
* RE, MI, FA, SOL, LA, SI, DO (where LA is 440Hz)
|
* RE, MI, FA, SOL, LA, SI, DO (where LA is 440Hz)
|
||||||
* RE2, MI2, FA2, SOL2, LA2, SI2, DO2 (where LA is 880Hz).
|
* RE2, MI2, FA2, SOL2, LA2, SI2, DO2 (where LA is 880Hz).
|
||||||
|
|
||||||
Length is any integer you want. It will define the length of the note (play with both length and bpm params to get what you want).
|
Length is any integer you want. It will define the length of the note (play with both _length_ and _bpm_ (during playback) params to get what you want).
|
||||||
|
|
||||||
You can use the -o (--output) option with a filename as argument to store the generated music sheet to this specific file.
|
You can use the _-o_ (_--output_) option with a filename as argument to store the generated music sheet to this specific file.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
### TLDR;
|
### TLDR;
|
||||||
|
227
generateur.c
227
generateur.c
@ -3,117 +3,170 @@
|
|||||||
# include "string.h"
|
# include "string.h"
|
||||||
# include "math.h"
|
# include "math.h"
|
||||||
# include "wave_stuff.h"
|
# include "wave_stuff.h"
|
||||||
|
# include "getopt.h"
|
||||||
# ifndef M_PI
|
# ifndef M_PI
|
||||||
# define M_PI 3.14159265358979323846
|
# define M_PI 3.14159265358979323846
|
||||||
# endif
|
# endif
|
||||||
# define TAILLE_MAX 100
|
# define TAILLE_MAX 100
|
||||||
|
|
||||||
char **str_split (char *s, const char *ct)
|
char **str_split (char *s, const char *ct)
|
||||||
{
|
{
|
||||||
char **tab = NULL;
|
char **tab = NULL;
|
||||||
|
|
||||||
if (s != NULL && ct != NULL)
|
if (s != NULL && ct != NULL)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char *cs = NULL;
|
char *cs = NULL;
|
||||||
size_t size = 1;
|
size_t size = 1;
|
||||||
|
|
||||||
/* (1) */
|
/* (1) */
|
||||||
for (i = 0; (cs = strtok (s, ct)); i++)
|
for (i = 0; (cs = strtok (s, ct)); i++)
|
||||||
{
|
{
|
||||||
if (size <= i + 1)
|
if (size <= i + 1)
|
||||||
{
|
|
||||||
void *tmp = NULL;
|
|
||||||
|
|
||||||
/* (2) */
|
|
||||||
size <<= 1;
|
|
||||||
tmp = realloc (tab, sizeof (*tab) * size);
|
|
||||||
if (tmp != NULL)
|
|
||||||
{
|
{
|
||||||
tab = tmp;
|
void *tmp = NULL;
|
||||||
|
|
||||||
|
/* (2) */
|
||||||
|
size <<= 1;
|
||||||
|
tmp = realloc (tab, sizeof (*tab) * size);
|
||||||
|
if (tmp != NULL)
|
||||||
|
{
|
||||||
|
tab = tmp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Memoire insuffisante\n");
|
||||||
|
free (tab);
|
||||||
|
tab = NULL;
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
/* (3) */
|
||||||
{
|
tab[i] = cs;
|
||||||
fprintf (stderr, "Memoire insuffisante\n");
|
s = NULL;
|
||||||
free (tab);
|
}
|
||||||
tab = NULL;
|
tab[i] = NULL;
|
||||||
exit (EXIT_FAILURE);
|
}
|
||||||
}
|
return tab;
|
||||||
}
|
|
||||||
/* (3) */
|
|
||||||
tab[i] = cs;
|
|
||||||
s = NULL;
|
|
||||||
}
|
|
||||||
tab[i] = NULL;
|
|
||||||
}
|
|
||||||
return tab;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void generer_note(int freq, int note, int duree, float *xd, int start)
|
void generer_note(int freq, int note, int duree, float *xd, int start)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = start; i < start+duree; i++)
|
for (i = start; i < start+duree; i++)
|
||||||
{
|
{
|
||||||
xd[i] += (int)(32767 *sin(2*M_PI*note*i/freq));
|
xd[i] += (int)(32767 *sin(2*M_PI*note*i/freq));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_help() {
|
||||||
|
fprintf(stderr, "\t\t\t\t================\n");
|
||||||
|
fprintf(stderr, "\t\t\t\t|| SongPlayer ||\n");
|
||||||
|
fprintf(stderr, "\t\t\t\t================\n\n");
|
||||||
|
fprintf(stderr, "Usage :\n");
|
||||||
|
fprintf(stderr, "=======\n\tgenererateur.out options\n\n");
|
||||||
|
fprintf(stderr, "Options :\n");
|
||||||
|
fprintf(stderr, "=========\n");
|
||||||
|
fprintf(stderr, "\t-h\t\t--help\t\t\tPrint this help message.\n");
|
||||||
|
fprintf(stderr, "\t-o file\t\t--output file\t\tSpecify the output wave file (mandatory).\n");
|
||||||
|
fprintf(stderr, "\t-b bpm\t\t--bpm bpm\t\tSpecify the speed in bpm to play the song (mandatory).\n");
|
||||||
|
fprintf(stderr, "\t-m musicsheet\t--musicsheet\t\tSpecify the input music sheet to use (mandatory).\n");
|
||||||
|
fprintf(stderr, "\t-s\t\t--silence\t\tAdd some silences between notes (optional).\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
if (argc < 5)
|
float *xd;
|
||||||
{
|
int nx = 0, freq = 44100, canal = 0, verbose = 0, BitsPerSample = 16, dureeNote = 0, start = 0, n = 0, silence = 0, Split1, Split2;
|
||||||
fprintf(stderr,"Usage: %s partition output.wav bpm silence\nsilence should be 1 to add silence between notes.\n",argv[0]);
|
float time = 0.5;
|
||||||
return 0;
|
char ligne[TAILLE_MAX];
|
||||||
}
|
char* output = NULL;
|
||||||
|
FILE* musicsheet = NULL;
|
||||||
float *xd;
|
|
||||||
int nx = 0, freq = 44100, canal = 0, verbose = 0, BitsPerSample = 16, dureeNote = 0, start = 0, n = 0, silence, Split1, Split2;
|
|
||||||
float time = 1./atof(argv[3])*60.;
|
|
||||||
char ligne[TAILLE_MAX];
|
|
||||||
FILE* partition = NULL;
|
|
||||||
|
|
||||||
partition = fopen(argv[1], "r");
|
|
||||||
fgets(ligne, TAILLE_MAX, partition);
|
|
||||||
n = atoi(ligne);
|
|
||||||
silence = atoi(argv[4]);
|
|
||||||
|
|
||||||
if(silence == 1)
|
|
||||||
{
|
|
||||||
nx = (int)(freq*time*(n+n/8));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nx = (int)(freq*time*n);
|
|
||||||
}
|
|
||||||
|
|
||||||
dureeNote = (int)(freq*time);
|
|
||||||
xd = (float*)calloc(nx,sizeof(float));
|
|
||||||
|
|
||||||
while(fgets(ligne, TAILLE_MAX, partition) != NULL)
|
const char* const short_options = "hm:b:o:s";
|
||||||
{
|
const struct option long_options[] = {
|
||||||
if(strchr(ligne, ':')!=NULL)
|
{ "help", 0, NULL, 'h' },
|
||||||
|
{ "bpm", 1, NULL, 'b' },
|
||||||
|
{ "musicsheet", 1, NULL, 'm' },
|
||||||
|
{ "output", 1, NULL, 'o' },
|
||||||
|
{ "silence", 0, NULL, 's' },
|
||||||
|
{ NULL, 0, NULL, 0 }
|
||||||
|
};
|
||||||
|
int next_option = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
next_option = getopt_long(argc, argv, short_options, long_options, NULL);
|
||||||
|
|
||||||
|
switch(next_option)
|
||||||
|
{
|
||||||
|
case 'h':
|
||||||
|
print_help();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'm':
|
||||||
|
musicsheet = fopen(optarg, "r");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'o':
|
||||||
|
output = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
silence = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
time = 1./atof(optarg)*60.;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(next_option != -1);
|
||||||
|
|
||||||
|
if(musicsheet == NULL || output == NULL) {
|
||||||
|
print_help();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
fgets(ligne, TAILLE_MAX, musicsheet);
|
||||||
|
n = atoi(ligne);
|
||||||
|
|
||||||
|
if(silence == 1)
|
||||||
{
|
{
|
||||||
char** Split=str_split(ligne, ":");
|
nx = (int)(freq*time*(n+n/8));
|
||||||
Split1=atoi(Split[0]);
|
|
||||||
Split2=atoi(Split[1]);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Split1=atoi(ligne);
|
nx = (int)(freq*time*n);
|
||||||
Split2=1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
generer_note(freq, Split1, Split2*dureeNote, xd, start);
|
dureeNote = (int)(freq*time);
|
||||||
start += Split2*dureeNote;
|
xd = (float*)calloc(nx,sizeof(float));
|
||||||
|
|
||||||
if(silence == 1)
|
while(fgets(ligne, TAILLE_MAX, musicsheet) != NULL)
|
||||||
{
|
{
|
||||||
generer_note(freq, 0, (int)(Split2*dureeNote/8), xd, start);
|
if(strchr(ligne, ':')!=NULL)
|
||||||
start += (int)(Split2*dureeNote/8);
|
{
|
||||||
|
char** Split=str_split(ligne, ":");
|
||||||
|
Split1=atoi(Split[0]);
|
||||||
|
Split2=atoi(Split[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Split1=atoi(ligne);
|
||||||
|
Split2=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
generer_note(freq, Split1, Split2*dureeNote, xd, start);
|
||||||
|
start += Split2*dureeNote;
|
||||||
|
|
||||||
|
if(silence == 1)
|
||||||
|
{
|
||||||
|
generer_note(freq, 0, (int)(Split2*dureeNote/8), xd, start);
|
||||||
|
start += (int)(Split2*dureeNote/8);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
save_wave_from_array(xd, nx, output, freq, BitsPerSample);
|
||||||
save_wave_from_array(xd, nx, argv[2], freq, BitsPerSample);
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user