1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
/* $Id: glue-audio_file.c,v 1.7 2009-10-15 11:31:19 potyra Exp $
*
* file writing audio output plugin for FAUmachine
*
* Copyright (C) 2008-2009 FAUmachine Team <info@faumachine.org>.
* This program is free software. You can redistribute it and/or modify it
* under the terms of the GNU General Public License, either version 2 of
* the License, or (at your option) any later version. See COPYING.
*/
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include "glue-audio_internal.h"
static ao_info_t info =
{
"File writing audio output",
"file",
"Matthias Sand",
""
};
LIBAO_EXTERN(file);
static const struct _RiffWaveChunk {
uint32_t chunkID;
int32_t fileSize;
uint32_t riffType;
} riffWaveChunk = {
.chunkID = 0x46464952, /* 'RIFF' */
.fileSize = 4,
.riffType = 0x45564157, /* 'WAVE' */
};
static const struct _FormatChunk {
uint32_t chunkID;
int32_t chunkSize;
int16_t wFormatTag;
uint16_t wChannels;
uint32_t dwSamplesPerSec;
uint32_t dwAvgBytesPerSec;
uint16_t wBlockAlign;
uint16_t wBitsPerSample;
} formatChunk = {
.chunkID = 0x20746d66, /* 'fmt ' */
.chunkSize = 16,
.wFormatTag = 0x0001, /* PCM */
.wChannels = GLUE_AUDIO_CHANNELS,
.dwSamplesPerSec = GLUE_AUDIO_RATE,
.dwAvgBytesPerSec = GLUE_AUDIO_RATE
* GLUE_AUDIO_CHANNELS
* GLUE_AUDIO_FORMAT_BYTES,
.wBlockAlign = GLUE_AUDIO_CHANNELS
* GLUE_AUDIO_FORMAT_BYTES,
.wBitsPerSample = GLUE_AUDIO_FORMAT_BITS,
};
static const struct _DataChunkHeader {
uint32_t chunkID;
int32_t chunkSize;
} dataChunkHeader = {
.chunkID = 0x61746164, /* 'data' */
.chunkSize = 0,
};
#define DATA_OFFSET sizeof(struct _RiffWaveChunk) \
+ sizeof(struct _FormatChunk) \
+ sizeof(struct _DataChunkHeader)
#define BUFFERSIZE 65536
static FILE *fp = NULL;
static void
update_filesize(void)
{
int32_t total_size;
int32_t size;
size_t ret;
total_size = ftell(fp);
size = total_size - 8;
fseek(fp, 4, SEEK_SET);
ret = fwrite(&size, sizeof(size), 1, fp);
assert(ret == 1);
size = total_size - DATA_OFFSET;
fseek(fp, DATA_OFFSET - 4, SEEK_SET);
ret = fwrite(&size, sizeof(size), 1, fp);
assert(ret == 1);
fseek(fp, 0, SEEK_END);
}
/* open & setup audio device
* return: 1=success 0=fail */
static int
init(void)
{
static int auto_nr = 0;
char path[32];
unsigned int nr;
size_t ret;
nr = auto_nr;
do {
auto_nr = (auto_nr + 1) % 1000;
sprintf(path, "audio-%03d.wav", auto_nr);
if (access(path, F_OK) != 0) {
break;
}
} while (nr != auto_nr);
if (nr == auto_nr) {
return 0;
}
nr = auto_nr;
sprintf(path, "audio-%03d.wav", nr);
fp = fopen(path, "w");
if (fp == NULL) {
return 0;
}
ret = fwrite(&riffWaveChunk, sizeof(struct _RiffWaveChunk), 1, fp);
assert(ret == 1);
ret = fwrite(&formatChunk, sizeof(struct _FormatChunk), 1, fp);
assert(ret == 1);
ret = fwrite(&dataChunkHeader, sizeof(struct _DataChunkHeader), 1, fp);
assert(ret == 1);
update_filesize();
return 1;
}
/* close audio device */
static void
uninit(int immed)
{
if (fp) {
fclose(fp);
fp = NULL;
}
}
/* return: how many bytes can be played without blocking */
static int
get_space()
{
return BUFFERSIZE;
}
/* plays 'len' bytes of 'data'
* return: number of bytes played */
static int
play(void *data, int len)
{
assert(fp);
size_t ret;
ret = fwrite(data, 1, len, fp);
assert(ret == (size_t)len);
update_filesize();
return len;
}
/* return: delay in seconds between first and last sample */
static float
get_delay(void)
{
return 0.0;
}
|