1 /** 2 * @file aufile.c Audio File interface 3 * 4 * Copyright (C) 2010 Creytiv.com 5 */ 6 #include <string.h> 7 #include <re.h> 8 #include <rem_au.h> 9 #include <rem_aufile.h> 10 #include "aufile.h" 11 12 13 /** Audio file state */ 14 struct aufile { 15 struct aufile_prm prm; 16 enum aufile_mode mode; 17 size_t datasize; 18 size_t nread; 19 size_t nwritten; 20 FILE *f; 21 }; 22 23 24 static int wavfmt_to_aufmt(enum wavfmt fmt, uint16_t bps) 25 { 26 switch (fmt) { 27 28 case WAVE_FMT_PCM: 29 if (bps != 16) 30 return -1; 31 32 return AUFMT_S16LE; 33 34 case WAVE_FMT_ALAW: 35 if (bps != 8) 36 return -1; 37 38 return AUFMT_PCMA; 39 40 case WAVE_FMT_ULAW: 41 if (bps != 8) 42 return -1; 43 44 return AUFMT_PCMU; 45 46 default: 47 return -1; 48 } 49 } 50 51 52 static enum wavfmt aufmt_to_wavfmt(enum aufmt fmt) 53 { 54 switch (fmt) { 55 56 case AUFMT_S16LE: return WAVE_FMT_PCM; 57 case AUFMT_PCMA: return WAVE_FMT_ALAW; 58 case AUFMT_PCMU: return WAVE_FMT_ULAW; 59 default: return -1; 60 } 61 } 62 63 64 static uint16_t aufmt_to_bps(enum aufmt fmt) 65 { 66 switch (fmt) { 67 68 case AUFMT_S16LE: return 16; 69 case AUFMT_PCMA: return 8; 70 case AUFMT_PCMU: return 8; 71 default: return 0; 72 } 73 } 74 75 76 static void destructor(void *arg) 77 { 78 struct aufile *af = arg; 79 80 if (!af->f) 81 return; 82 83 /* Update WAV header in write-mode */ 84 if (af->mode == AUFILE_WRITE && af->nwritten > 0) { 85 86 rewind(af->f); 87 88 (void)wav_header_encode(af->f, aufmt_to_wavfmt(af->prm.fmt), 89 af->prm.channels, af->prm.srate, 90 aufmt_to_bps(af->prm.fmt), 91 af->nwritten); 92 } 93 94 (void)fclose(af->f); 95 } 96 97 98 /** 99 * Open a WAVE file for reading or writing 100 * 101 * Supported formats: 16-bit PCM, A-law, U-law 102 * 103 * @param afp Pointer to allocated Audio file 104 * @param prm Audio format of the file 105 * @param filename Filename of the WAV-file to load 106 * @param mode Read or write mode 107 * 108 * @return 0 if success, otherwise errorcode 109 */ 110 int aufile_open(struct aufile **afp, struct aufile_prm *prm, 111 const char *filename, enum aufile_mode mode) 112 { 113 struct wav_fmt fmt; 114 struct aufile *af; 115 int aufmt; 116 int err; 117 118 if (!afp || !filename || (mode == AUFILE_WRITE && !prm)) 119 return EINVAL; 120 121 af = mem_zalloc(sizeof(*af), destructor); 122 if (!af) 123 return ENOMEM; 124 125 af->mode = mode; 126 127 af->f = fopen(filename, mode == AUFILE_READ ? "rb" : "wb"); 128 if (!af->f) { 129 err = errno; 130 goto out; 131 } 132 133 switch (mode) { 134 135 case AUFILE_READ: 136 err = wav_header_decode(&fmt, &af->datasize, af->f); 137 if (err) 138 goto out; 139 140 aufmt = wavfmt_to_aufmt(fmt.format, fmt.bps); 141 if (aufmt < 0) { 142 err = ENOSYS; 143 goto out; 144 } 145 146 if (prm) { 147 prm->srate = fmt.srate; 148 prm->channels = (uint8_t)fmt.channels; 149 prm->fmt = aufmt; 150 } 151 break; 152 153 case AUFILE_WRITE: 154 af->prm = *prm; 155 156 err = wav_header_encode(af->f, aufmt_to_wavfmt(prm->fmt), 157 prm->channels, prm->srate, 158 aufmt_to_bps(prm->fmt), 0); 159 break; 160 161 default: 162 err = ENOSYS; 163 break; 164 } 165 166 out: 167 if (err) 168 mem_deref(af); 169 else 170 *afp = af; 171 172 return err; 173 } 174 175 176 /** 177 * Read PCM-samples from a WAV file 178 * 179 * @param af Audio-file 180 * @param p Read buffer 181 * @param sz Size of buffer, on return contains actual read 182 * 183 * @return 0 if success, otherwise errorcode 184 */ 185 int aufile_read(struct aufile *af, uint8_t *p, size_t *sz) 186 { 187 size_t n; 188 189 if (!af || !p || !sz || af->mode != AUFILE_READ) 190 return EINVAL; 191 192 if (af->nread >= af->datasize) { 193 *sz = 0; 194 return 0; 195 } 196 197 n = min(*sz, af->datasize - af->nread); 198 199 n = fread(p, 1, n, af->f); 200 if (ferror(af->f)) 201 return errno; 202 203 *sz = n; 204 af->nread += n; 205 206 return 0; 207 } 208 209 210 /** 211 * Write PCM-samples to a WAV file 212 * 213 * @param af Audio-file 214 * @param p Write buffer 215 * @param sz Size of buffer 216 * 217 * @return 0 if success, otherwise errorcode 218 */ 219 int aufile_write(struct aufile *af, const uint8_t *p, size_t sz) 220 { 221 if (!af || !p || !sz || af->mode != AUFILE_WRITE) 222 return EINVAL; 223 224 if (1 != fwrite(p, sz, 1, af->f)) 225 return ferror(af->f); 226 227 af->nwritten += sz; 228 229 return 0; 230 } 231