audiogen.c 7.25 KB
Newer Older
1
/*
2 3
 * Generate a synthetic stereo sound.
 * NOTE: No floats are used to guarantee bitexact output.
4 5 6
 *
 * Copyright (c) 2002 Fabrice Bellard
 *
7
 * This file is part of Libav.
8
 *
9
 * Libav is free software; you can redistribute it and/or
10 11 12 13
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
14
 * Libav is distributed in the hope that it will be useful,
15 16 17 18 19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
20
 * License along with Libav; if not, write to the Free Software
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
 */
23

24
#include <stdlib.h>
25
#include <stdint.h>
26
#include <stdio.h>
27
#include <string.h>
28

29
#define MAX_CHANNELS 8
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

static unsigned int myrnd(unsigned int *seed_ptr, int n)
{
    unsigned int seed, val;

    seed = *seed_ptr;
    seed = (seed * 314159) + 1;
    if (n == 256) {
        val = seed >> 24;
    } else {
        val = seed % n;
    }
    *seed_ptr = seed;
    return val;
}

#define FRAC_BITS 16
#define FRAC_ONE (1 << FRAC_BITS)

#define COS_TABLE_BITS 7

Diego Biurrun's avatar
Diego Biurrun committed
51
/* integer cosine */
52
static const unsigned short cos_table[(1 << COS_TABLE_BITS) + 2] = {
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
    0x8000, 0x7ffe, 0x7ff6, 0x7fea, 0x7fd9, 0x7fc2, 0x7fa7, 0x7f87,
    0x7f62, 0x7f38, 0x7f0a, 0x7ed6, 0x7e9d, 0x7e60, 0x7e1e, 0x7dd6,
    0x7d8a, 0x7d3a, 0x7ce4, 0x7c89, 0x7c2a, 0x7bc6, 0x7b5d, 0x7aef,
    0x7a7d, 0x7a06, 0x798a, 0x790a, 0x7885, 0x77fb, 0x776c, 0x76d9,
    0x7642, 0x75a6, 0x7505, 0x7460, 0x73b6, 0x7308, 0x7255, 0x719e,
    0x70e3, 0x7023, 0x6f5f, 0x6e97, 0x6dca, 0x6cf9, 0x6c24, 0x6b4b,
    0x6a6e, 0x698c, 0x68a7, 0x67bd, 0x66d0, 0x65de, 0x64e9, 0x63ef,
    0x62f2, 0x61f1, 0x60ec, 0x5fe4, 0x5ed7, 0x5dc8, 0x5cb4, 0x5b9d,
    0x5a82, 0x5964, 0x5843, 0x571e, 0x55f6, 0x54ca, 0x539b, 0x5269,
    0x5134, 0x4ffb, 0x4ec0, 0x4d81, 0x4c40, 0x4afb, 0x49b4, 0x486a,
    0x471d, 0x45cd, 0x447b, 0x4326, 0x41ce, 0x4074, 0x3f17, 0x3db8,
    0x3c57, 0x3af3, 0x398d, 0x3825, 0x36ba, 0x354e, 0x33df, 0x326e,
    0x30fc, 0x2f87, 0x2e11, 0x2c99, 0x2b1f, 0x29a4, 0x2827, 0x26a8,
    0x2528, 0x23a7, 0x2224, 0x209f, 0x1f1a, 0x1d93, 0x1c0c, 0x1a83,
    0x18f9, 0x176e, 0x15e2, 0x1455, 0x12c8, 0x113a, 0x0fab, 0x0e1c,
    0x0c8c, 0x0afb, 0x096b, 0x07d9, 0x0648, 0x04b6, 0x0324, 0x0192,
    0x0000, 0x0000,
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
};

#define CSHIFT (FRAC_BITS - COS_TABLE_BITS - 2)

static int int_cos(int a)
{
    int neg, v, f;
    const unsigned short *p;

    a = a & (FRAC_ONE - 1); /* modulo 2 * pi */
    if (a >= (FRAC_ONE / 2))
        a = FRAC_ONE - a;
    neg = 0;
    if (a > (FRAC_ONE / 4)) {
        neg = -1;
85
        a   = (FRAC_ONE / 2) - a;
86 87 88 89 90 91 92 93 94 95 96 97
    }
    p = cos_table + (a >> CSHIFT);
    /* linear interpolation */
    f = a & ((1 << CSHIFT) - 1);
    v = p[0] + (((p[1] - p[0]) * f + (1 << (CSHIFT - 1))) >> CSHIFT);
    v = (v ^ neg) - neg;
    v = v << (FRAC_BITS - 15);
    return v;
}

FILE *outfile;

98
static void put16(int16_t v)
99
{
100
    fputc( v       & 0xff, outfile);
101 102 103
    fputc((v >> 8) & 0xff, outfile);
}

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
static void put32(uint32_t v)
{
    fputc( v        & 0xff, outfile);
    fputc((v >>  8) & 0xff, outfile);
    fputc((v >> 16) & 0xff, outfile);
    fputc((v >> 24) & 0xff, outfile);
}

#define HEADER_SIZE      46
#define FMT_SIZE         18
#define SAMPLE_SIZE       2
#define WFORMAT_PCM  0x0001

static void put_wav_header(int sample_rate, int channels, int nb_samples)
{
    int block_align = SAMPLE_SIZE * channels;
    int data_size   = block_align * nb_samples;

    fputs("RIFF", outfile);
    put32(HEADER_SIZE + data_size);
    fputs("WAVEfmt ", outfile);
    put32(FMT_SIZE);
    put16(WFORMAT_PCM);
    put16(channels);
    put32(sample_rate);
    put32(block_align * sample_rate);
    put16(block_align);
    put16(SAMPLE_SIZE * 8);
    put16(0);
    fputs("data", outfile);
    put32(data_size);
}

137 138 139 140
int main(int argc, char **argv)
{
    int i, a, v, j, f, amp, ampa;
    unsigned int seed = 1;
141 142 143 144
    int tabf1[MAX_CHANNELS], tabf2[MAX_CHANNELS];
    int taba[MAX_CHANNELS];
    int sample_rate = 44100;
    int nb_channels = 2;
145
    char *ext;
146

147 148
    if (argc < 2 || argc > 5) {
        printf("usage: %s file [<sample rate> [<channels>] [<random seed>]]\n"
149
               "generate a test raw 16 bit audio stream\n"
150
               "If the file extension is .wav a WAVE header will be added.\n"
151
               "default: 44100 Hz stereo\n", argv[0]);
152 153
        exit(1);
    }
154

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
    if (argc > 2) {
        sample_rate = atoi(argv[2]);
        if (sample_rate <= 0) {
            fprintf(stderr, "invalid sample rate: %d\n", sample_rate);
            return 1;
        }
    }

    if (argc > 3) {
        nb_channels = atoi(argv[3]);
        if (nb_channels < 1 || nb_channels > MAX_CHANNELS) {
            fprintf(stderr, "invalid number of channels: %d\n", nb_channels);
            return 1;
        }
    }

171 172 173
    if (argc > 4)
        seed = atoi(argv[4]);

174
    outfile = fopen(argv[1], "wb");
175 176 177 178 179
    if (!outfile) {
        perror(argv[1]);
        return 1;
    }

180
    if ((ext = strrchr(argv[1], '.')) && !strcmp(ext, ".wav"))
181 182
        put_wav_header(sample_rate, nb_channels, 6 * sample_rate);

Diego Biurrun's avatar
Diego Biurrun committed
183
    /* 1 second of single freq sine at 1000 Hz */
184
    a = 0;
185
    for (i = 0; i < 1 * sample_rate; i++) {
186
        v = (int_cos(a) * 10000) >> FRAC_BITS;
187
        for (j = 0; j < nb_channels; j++)
188
            put16(v);
189
        a += (1000 * FRAC_ONE) / sample_rate;
190 191
    }

Diego Biurrun's avatar
Diego Biurrun committed
192
    /* 1 second of varying frequency between 100 and 10000 Hz */
193
    a = 0;
194
    for (i = 0; i < 1 * sample_rate; i++) {
195
        v = (int_cos(a) * 10000) >> FRAC_BITS;
196
        for (j = 0; j < nb_channels; j++)
197
            put16(v);
198
        f  = 100 + (((10000 - 100) * i) / sample_rate);
199
        a += (f * FRAC_ONE) / sample_rate;
200
    }
201

202
    /* 0.5 second of low amplitude white noise */
203
    for (i = 0; i < sample_rate / 2; i++) {
204
        v = myrnd(&seed, 20000) - 10000;
205
        for (j = 0; j < nb_channels; j++)
206
            put16(v);
207 208 209
    }

    /* 0.5 second of high amplitude white noise */
210
    for (i = 0; i < sample_rate / 2; i++) {
211
        v = myrnd(&seed, 65535) - 32768;
212
        for (j = 0; j < nb_channels; j++)
213
            put16(v);
214 215
    }

216
    /* 1 second of unrelated ramps for each channel */
217 218
    for (j = 0; j < nb_channels; j++) {
        taba[j]  = 0;
219 220 221
        tabf1[j] = 100 + myrnd(&seed, 5000);
        tabf2[j] = 100 + myrnd(&seed, 5000);
    }
222 223
    for (i = 0; i < 1 * sample_rate; i++) {
        for (j = 0; j < nb_channels; j++) {
224
            v = (int_cos(taba[j]) * 10000) >> FRAC_BITS;
225
            put16(v);
226
            f        = tabf1[j] + (((tabf2[j] - tabf1[j]) * i) / sample_rate);
227
            taba[j] += (f * FRAC_ONE) / sample_rate;
228 229
        }
    }
230

231
    /* 2 seconds of 500 Hz with varying volume */
232
    a    = 0;
233
    ampa = 0;
234 235
    for (i = 0; i < 2 * sample_rate; i++) {
        for (j = 0; j < nb_channels; j++) {
236 237 238 239
            amp = ((FRAC_ONE + int_cos(ampa)) * 5000) >> FRAC_BITS;
            if (j & 1)
                amp = 10000 - amp;
            v = (int_cos(a) * amp) >> FRAC_BITS;
240
            put16(v);
241
            a    += (500 * FRAC_ONE) / sample_rate;
242
            ampa += (2 * FRAC_ONE) / sample_rate;
243 244 245 246 247 248
        }
    }

    fclose(outfile);
    return 0;
}