Fichiers audio, journal, annales
This commit is contained in:
153
cours/audio/main.c
Normal file
153
cours/audio/main.c
Normal file
@@ -0,0 +1,153 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <sndfile.h>
|
||||
|
||||
#include "audio.h"
|
||||
#include "vcd.h"
|
||||
|
||||
const size_t sample_rate = Audio__period;
|
||||
|
||||
void die(const char *message) {
|
||||
fprintf(stderr, message);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
SNDFILE *file_out = NULL;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Audio__main_mem mem;
|
||||
Audio__main_out res;
|
||||
SDL_AudioSpec spec;
|
||||
SDL_AudioDeviceID dev;
|
||||
int opt = -1;
|
||||
bool quiet = false;
|
||||
size_t max_sec = SIZE_MAX; /* largest value of type size_t */
|
||||
const char *filename = NULL;
|
||||
Uint32 buffered;
|
||||
|
||||
while ((opt = getopt(argc, argv, "ho:qm:t:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
printf("Usage: %s OPTIONS\n", argv[0]);
|
||||
printf("Options:\n");
|
||||
printf(" -o <file.wav> write samples to <file.wav>\n");
|
||||
printf(" -q do not play sound\n");
|
||||
printf(" -m <sec> play for <sec> seconds\n");
|
||||
printf(" -t <file.vcd> dump traces in <file.vcd>\n");
|
||||
printf(" -h display this message\n");
|
||||
return 0;
|
||||
case 'q':
|
||||
quiet = true;
|
||||
break;
|
||||
case 'o':
|
||||
filename = optarg;
|
||||
break;
|
||||
case 'm':
|
||||
max_sec = atoi(optarg);
|
||||
break;
|
||||
case 't':
|
||||
hept_vcd_init(optarg, VCD_TIME_UNIT_US, 20);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown option '%c'\n", opt);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (SDL_Init(SDL_INIT_AUDIO) < 0)
|
||||
die("Could not initialize SDL2\n");
|
||||
|
||||
/* Specification of requested output device. */
|
||||
bzero(&spec, sizeof spec);
|
||||
spec.freq = sample_rate; /* Samples per second */
|
||||
spec.format = AUDIO_F32; /* Sample format: IEEE-754 32 bits */
|
||||
spec.channels = 2; /* Two channels */
|
||||
spec.samples = 4096; /* Buffers sized 4 KiB */
|
||||
spec.callback = NULL;
|
||||
|
||||
if (!(dev = SDL_OpenAudioDevice(NULL, 0, &spec, NULL, 0)))
|
||||
die("Could not open audio device\n");
|
||||
|
||||
if (filename != NULL) {
|
||||
/* Specification of requested output file, if any. */
|
||||
SF_INFO info_out;
|
||||
bzero(&info_out, sizeof info_out);
|
||||
info_out.channels = 2; /* Two channels */
|
||||
info_out.samplerate = sample_rate; /* Samples per second */
|
||||
info_out.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; /* File format */
|
||||
|
||||
if (!(file_out = sf_open(filename, SFM_WRITE, &info_out))) {
|
||||
fprintf(stderr, "Could not open WAV file %s for writing\n", argv[1]);
|
||||
SDL_Quit();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
Audio__main_reset(&mem);
|
||||
float *buffer = calloc(spec.samples, sizeof *buffer);
|
||||
SDL_PauseAudioDevice(dev, 0);
|
||||
|
||||
/* Loop until we've produced the requested amount of samples, that is the
|
||||
duration in seconds multiplied by the number of samples per second. This
|
||||
number of samples shall be sent on each of both stereo channels.
|
||||
|
||||
Each iteration sends spec.samples stereo samples to the audio device,
|
||||
hence we halve it to get the number of generated samples per-channel. */
|
||||
for (size_t samples = 0;
|
||||
samples < max_sec * sample_rate;
|
||||
samples += spec.samples / 2) {
|
||||
|
||||
/* Print sound progress. */
|
||||
printf("\rSent %08zu samples", samples);
|
||||
if (max_sec != SIZE_MAX) {
|
||||
printf(" (%2.0f%)", 100. * (double)samples / (max_sec * sample_rate));
|
||||
}
|
||||
fflush(stdout);
|
||||
|
||||
/* Exit immediately if requested, e.g., the user pressed Ctrl-C. */
|
||||
if (SDL_QuitRequested()) {
|
||||
printf("\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Step the node as much as necessary to fill a buffer. Each step produces
|
||||
one stereo sample. */
|
||||
for (size_t i = 0; i < spec.samples; i += 2) {
|
||||
Audio__main_step(&res, &mem);
|
||||
buffer[i+0] = res.o.l;
|
||||
buffer[i+1] = res.o.r;
|
||||
}
|
||||
|
||||
/* Send the generated sound to the sound card and/or file. */
|
||||
if (!quiet)
|
||||
SDL_QueueAudio(dev, buffer, spec.samples * sizeof *buffer);
|
||||
if (file_out)
|
||||
sf_writef_float(file_out, buffer, spec.samples / 2);
|
||||
|
||||
/* Throttle queued audio, otherwise we will certainly end up consuming all
|
||||
available memory. */
|
||||
buffered = SDL_GetQueuedAudioSize(dev);
|
||||
while (!quiet && buffered >= 1 << 22) {
|
||||
SDL_Delay(50);
|
||||
buffered = SDL_GetQueuedAudioSize(dev);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* Wait until the audio buffer is empty. */
|
||||
printf("Waiting for queue flush... "); fflush(stdout);
|
||||
while ((buffered = SDL_GetQueuedAudioSize(dev)) != 0)
|
||||
SDL_Delay(50);
|
||||
printf("done.\n");
|
||||
|
||||
free(buffer);
|
||||
if (file_out)
|
||||
sf_close(file_out);
|
||||
SDL_Quit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user