1e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung/*
2e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung * Copyright (C) 2014 The Android Open Source Project
3e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung *
4e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung * Licensed under the Apache License, Version 2.0 (the "License");
5e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung * you may not use this file except in compliance with the License.
6e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung * You may obtain a copy of the License at
7e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung *
8e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung *      http://www.apache.org/licenses/LICENSE-2.0
9e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung *
10e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung * Unless required by applicable law or agreed to in writing, software
11e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung * distributed under the License is distributed on an "AS IS" BASIS,
12e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung * See the License for the specific language governing permissions and
14e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung * limitations under the License.
15e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung */
16e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
17e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung#include <stdio.h>
18e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung#include <inttypes.h>
19e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung#include <math.h>
20e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung#include <vector>
21e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung#include <audio_utils/primitives.h>
22e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung#include <audio_utils/sndfile.h>
23e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung#include <media/AudioBufferProvider.h>
24068561c8e84569d51df2adbbb53b56fdfd09c06bAndy Hung#include <media/AudioMixer.h>
25e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung#include "test_utils.h"
26e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
27e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung/* Testing is typically through creation of an output WAV file from several
28e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung * source inputs, to be later analyzed by an audio program such as Audacity.
29e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung *
30e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung * Sine or chirp functions are typically more useful as input to the mixer
31e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung * as they show up as straight lines on a spectrogram if successfully mixed.
32e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung *
33e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung * A sample shell script is provided: mixer_to_wave_tests.sh
34e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung */
35e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
36e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hungusing namespace android;
37e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
38e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hungstatic void usage(const char* name) {
39e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    fprintf(stderr, "Usage: %s [-f] [-m] [-c channels]"
40e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                    " [-s sample-rate] [-o <output-file>] [-a <aux-buffer-file>] [-P csv]"
41e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                    " (<input-file> | <command>)+\n", name);
427f47549516ae5938759b5c834c8423378a60b3d8Andy Hung    fprintf(stderr, "    -f    enable floating point input track by default\n");
43e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    fprintf(stderr, "    -m    enable floating point mixer output\n");
44e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    fprintf(stderr, "    -c    number of mixer output channels\n");
45e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    fprintf(stderr, "    -s    mixer sample-rate\n");
46e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    fprintf(stderr, "    -o    <output-file> WAV file, pcm16 (or float if -m specified)\n");
47e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    fprintf(stderr, "    -a    <aux-buffer-file>\n");
48e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    fprintf(stderr, "    -P    # frames provided per call to resample() in CSV format\n");
49e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    fprintf(stderr, "    <input-file> is a WAV file\n");
507f47549516ae5938759b5c834c8423378a60b3d8Andy Hung    fprintf(stderr, "    <command> can be 'sine:[(i|f),]<channels>,<frequency>,<samplerate>'\n");
517f47549516ae5938759b5c834c8423378a60b3d8Andy Hung    fprintf(stderr, "                     'chirp:[(i|f),]<channels>,<samplerate>'\n");
52e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung}
53e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
54e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hungstatic int writeFile(const char *filename, const void *buffer,
55e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        uint32_t sampleRate, uint32_t channels, size_t frames, bool isBufferFloat) {
56e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    if (filename == NULL) {
57e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        return 0; // ok to pass in NULL filename
58e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    }
59e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    // write output to file.
60e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    SF_INFO info;
61e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    info.frames = 0;
62e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    info.samplerate = sampleRate;
63e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    info.channels = channels;
64e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    info.format = SF_FORMAT_WAV | (isBufferFloat ? SF_FORMAT_FLOAT : SF_FORMAT_PCM_16);
65a4daf0b4f934b800a49f199fb8c09409391c8fc0Glenn Kasten    printf("saving file:%s  channels:%u  samplerate:%u  frames:%zu\n",
66e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            filename, info.channels, info.samplerate, frames);
67e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    SNDFILE *sf = sf_open(filename, SFM_WRITE, &info);
68e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    if (sf == NULL) {
69e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        perror(filename);
70e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        return EXIT_FAILURE;
71e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    }
72e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    if (isBufferFloat) {
73e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        (void) sf_writef_float(sf, (float*)buffer, frames);
74e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    } else {
75e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        (void) sf_writef_short(sf, (short*)buffer, frames);
76e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    }
77e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    sf_close(sf);
78e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    return EXIT_SUCCESS;
79e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung}
80e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
817f47549516ae5938759b5c834c8423378a60b3d8Andy Hungconst char *parseFormat(const char *s, bool *useFloat) {
827f47549516ae5938759b5c834c8423378a60b3d8Andy Hung    if (!strncmp(s, "f,", 2)) {
837f47549516ae5938759b5c834c8423378a60b3d8Andy Hung        *useFloat = true;
847f47549516ae5938759b5c834c8423378a60b3d8Andy Hung        return s + 2;
857f47549516ae5938759b5c834c8423378a60b3d8Andy Hung    }
867f47549516ae5938759b5c834c8423378a60b3d8Andy Hung    if (!strncmp(s, "i,", 2)) {
877f47549516ae5938759b5c834c8423378a60b3d8Andy Hung        *useFloat = false;
887f47549516ae5938759b5c834c8423378a60b3d8Andy Hung        return s + 2;
897f47549516ae5938759b5c834c8423378a60b3d8Andy Hung    }
907f47549516ae5938759b5c834c8423378a60b3d8Andy Hung    return s;
917f47549516ae5938759b5c834c8423378a60b3d8Andy Hung}
927f47549516ae5938759b5c834c8423378a60b3d8Andy Hung
93e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hungint main(int argc, char* argv[]) {
94e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    const char* const progname = argv[0];
95e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    bool useInputFloat = false;
96e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    bool useMixerFloat = false;
97e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    bool useRamp = true;
98e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    uint32_t outputSampleRate = 48000;
99e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    uint32_t outputChannels = 2; // stereo for now
100e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    std::vector<int> Pvalues;
101e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    const char* outputFilename = NULL;
102e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    const char* auxFilename = NULL;
1037f47549516ae5938759b5c834c8423378a60b3d8Andy Hung    std::vector<int32_t> names;
1047f47549516ae5938759b5c834c8423378a60b3d8Andy Hung    std::vector<SignalProvider> providers;
1057f47549516ae5938759b5c834c8423378a60b3d8Andy Hung    std::vector<audio_format_t> formats;
106e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
107e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    for (int ch; (ch = getopt(argc, argv, "fmc:s:o:a:P:")) != -1;) {
108e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        switch (ch) {
109e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        case 'f':
110e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            useInputFloat = true;
111e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            break;
112e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        case 'm':
113e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            useMixerFloat = true;
114e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            break;
115e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung        case 'c':
116e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            outputChannels = atoi(optarg);
117e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            break;
118e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        case 's':
119e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            outputSampleRate = atoi(optarg);
120e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            break;
121e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        case 'o':
122e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            outputFilename = optarg;
123e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            break;
124e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        case 'a':
125e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            auxFilename = optarg;
126e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            break;
127e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        case 'P':
128e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            if (parseCSV(optarg, Pvalues) < 0) {
129e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                fprintf(stderr, "incorrect syntax for -P option\n");
130e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                return EXIT_FAILURE;
131e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            }
132e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            break;
133e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        case '?':
134e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        default:
135e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            usage(progname);
136e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            return EXIT_FAILURE;
137e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        }
138e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    }
139e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    argc -= optind;
140e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    argv += optind;
141e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
142e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    if (argc == 0) {
143e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        usage(progname);
144e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        return EXIT_FAILURE;
145e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    }
146e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    if ((unsigned)argc > AudioMixer::MAX_NUM_TRACKS) {
147e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        fprintf(stderr, "too many tracks: %d > %u", argc, AudioMixer::MAX_NUM_TRACKS);
148e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        return EXIT_FAILURE;
149e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    }
150e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
151e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    size_t outputFrames = 0;
152e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
153e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    // create providers for each track
1547f47549516ae5938759b5c834c8423378a60b3d8Andy Hung    names.resize(argc);
1557f47549516ae5938759b5c834c8423378a60b3d8Andy Hung    providers.resize(argc);
1567f47549516ae5938759b5c834c8423378a60b3d8Andy Hung    formats.resize(argc);
157e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    for (int i = 0; i < argc; ++i) {
158e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        static const char chirp[] = "chirp:";
159e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        static const char sine[] = "sine:";
160e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        static const double kSeconds = 1;
1617f47549516ae5938759b5c834c8423378a60b3d8Andy Hung        bool useFloat = useInputFloat;
162e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
163e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        if (!strncmp(argv[i], chirp, strlen(chirp))) {
164e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            std::vector<int> v;
1657f47549516ae5938759b5c834c8423378a60b3d8Andy Hung            const char *s = parseFormat(argv[i] + strlen(chirp), &useFloat);
166e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
1677f47549516ae5938759b5c834c8423378a60b3d8Andy Hung            parseCSV(s, v);
168e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            if (v.size() == 2) {
169e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                printf("creating chirp(%d %d)\n", v[0], v[1]);
1707f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                if (useFloat) {
1717f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                    providers[i].setChirp<float>(v[0], 0, v[1]/2, v[1], kSeconds);
1727f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                    formats[i] = AUDIO_FORMAT_PCM_FLOAT;
173e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                } else {
1747f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                    providers[i].setChirp<int16_t>(v[0], 0, v[1]/2, v[1], kSeconds);
1757f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                    formats[i] = AUDIO_FORMAT_PCM_16_BIT;
176e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                }
1777f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                providers[i].setIncr(Pvalues);
178e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            } else {
179e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                fprintf(stderr, "malformed input '%s'\n", argv[i]);
180e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            }
181e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        } else if (!strncmp(argv[i], sine, strlen(sine))) {
182e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            std::vector<int> v;
1837f47549516ae5938759b5c834c8423378a60b3d8Andy Hung            const char *s = parseFormat(argv[i] + strlen(sine), &useFloat);
184e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
1857f47549516ae5938759b5c834c8423378a60b3d8Andy Hung            parseCSV(s, v);
186e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            if (v.size() == 3) {
187e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                printf("creating sine(%d %d %d)\n", v[0], v[1], v[2]);
1887f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                if (useFloat) {
1897f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                    providers[i].setSine<float>(v[0], v[1], v[2], kSeconds);
1907f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                    formats[i] = AUDIO_FORMAT_PCM_FLOAT;
191e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                } else {
1927f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                    providers[i].setSine<int16_t>(v[0], v[1], v[2], kSeconds);
1937f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                    formats[i] = AUDIO_FORMAT_PCM_16_BIT;
194e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                }
1957f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                providers[i].setIncr(Pvalues);
196e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            } else {
197e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                fprintf(stderr, "malformed input '%s'\n", argv[i]);
198e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            }
199e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        } else {
200e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            printf("creating filename(%s)\n", argv[i]);
201e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            if (useInputFloat) {
2027f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                providers[i].setFile<float>(argv[i]);
2037f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                formats[i] = AUDIO_FORMAT_PCM_FLOAT;
204e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            } else {
2057f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                providers[i].setFile<short>(argv[i]);
2067f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                formats[i] = AUDIO_FORMAT_PCM_16_BIT;
207e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            }
2087f47549516ae5938759b5c834c8423378a60b3d8Andy Hung            providers[i].setIncr(Pvalues);
209e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        }
210e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        // calculate the number of output frames
2117f47549516ae5938759b5c834c8423378a60b3d8Andy Hung        size_t nframes = (int64_t) providers[i].getNumFrames() * outputSampleRate
2127f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                / providers[i].getSampleRate();
213e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        if (i == 0 || outputFrames > nframes) { // choose minimum for outputFrames
214e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            outputFrames = nframes;
215e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        }
216e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    }
217e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
218e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    // create the output buffer.
219e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    const size_t outputFrameSize = outputChannels
220e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            * (useMixerFloat ? sizeof(float) : sizeof(int16_t));
221e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    const size_t outputSize = outputFrames * outputFrameSize;
222e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    const audio_channel_mask_t outputChannelMask =
223e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            audio_channel_out_mask_from_count(outputChannels);
224e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    void *outputAddr = NULL;
225e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    (void) posix_memalign(&outputAddr, 32, outputSize);
226e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    memset(outputAddr, 0, outputSize);
227e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
228e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    // create the aux buffer, if needed.
229e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    const size_t auxFrameSize = sizeof(int32_t); // Q4.27 always
230e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    const size_t auxSize = outputFrames * auxFrameSize;
231e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    void *auxAddr = NULL;
232e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    if (auxFilename) {
233e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        (void) posix_memalign(&auxAddr, 32, auxSize);
234e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        memset(auxAddr, 0, auxSize);
235e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    }
236e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
237e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    // create the mixer.
238e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    const size_t mixerFrameCount = 320; // typical numbers may range from 240 or 960
239e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    AudioMixer *mixer = new AudioMixer(mixerFrameCount, outputSampleRate);
240e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    audio_format_t mixerFormat = useMixerFloat
241e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            ? AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT;
2427f47549516ae5938759b5c834c8423378a60b3d8Andy Hung    float f = AudioMixer::UNITY_GAIN_FLOAT / providers.size(); // normalize volume by # tracks
243e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    static float f0; // zero
244e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
245e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    // set up the tracks.
2467f47549516ae5938759b5c834c8423378a60b3d8Andy Hung    for (size_t i = 0; i < providers.size(); ++i) {
2477f47549516ae5938759b5c834c8423378a60b3d8Andy Hung        //printf("track %d out of %d\n", i, providers.size());
2487f47549516ae5938759b5c834c8423378a60b3d8Andy Hung        uint32_t channelMask = audio_channel_out_mask_from_count(providers[i].getNumChannels());
249e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        int32_t name = mixer->getTrackName(channelMask,
2507f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                formats[i], AUDIO_SESSION_OUTPUT_MIX);
251e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        ALOG_ASSERT(name >= 0);
2527f47549516ae5938759b5c834c8423378a60b3d8Andy Hung        names[i] = name;
2537f47549516ae5938759b5c834c8423378a60b3d8Andy Hung        mixer->setBufferProvider(name, &providers[i]);
254e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
255e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                (void *)outputAddr);
256e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        mixer->setParameter(
257e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                name,
258e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                AudioMixer::TRACK,
259e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                AudioMixer::MIXER_FORMAT,
260e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                (void *)(uintptr_t)mixerFormat);
261e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung        mixer->setParameter(
262e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                name,
263e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                AudioMixer::TRACK,
264e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                AudioMixer::FORMAT,
2657f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                (void *)(uintptr_t)formats[i]);
266e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        mixer->setParameter(
267e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                name,
268e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                AudioMixer::TRACK,
269e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                AudioMixer::MIXER_CHANNEL_MASK,
270e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                (void *)(uintptr_t)outputChannelMask);
271e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung        mixer->setParameter(
272e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                name,
273e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                AudioMixer::TRACK,
274e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                AudioMixer::CHANNEL_MASK,
275e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                (void *)(uintptr_t)channelMask);
276e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung        mixer->setParameter(
277e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                name,
278e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                AudioMixer::RESAMPLE,
279e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                AudioMixer::SAMPLE_RATE,
2807f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                (void *)(uintptr_t)providers[i].getSampleRate());
281e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        if (useRamp) {
282e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &f0);
283e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &f0);
284e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            mixer->setParameter(name, AudioMixer::RAMP_VOLUME, AudioMixer::VOLUME0, &f);
285e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            mixer->setParameter(name, AudioMixer::RAMP_VOLUME, AudioMixer::VOLUME1, &f);
286e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        } else {
287e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &f);
288e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &f);
289e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        }
290e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        if (auxFilename) {
291e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::AUX_BUFFER,
292e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                    (void *) auxAddr);
293e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::AUXLEVEL, &f0);
294e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            mixer->setParameter(name, AudioMixer::RAMP_VOLUME, AudioMixer::AUXLEVEL, &f);
295e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        }
296e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        mixer->enable(name);
297e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    }
298e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
299e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    // pump the mixer to process data.
300e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    size_t i;
301e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    for (i = 0; i < outputFrames - mixerFrameCount; i += mixerFrameCount) {
3027f47549516ae5938759b5c834c8423378a60b3d8Andy Hung        for (size_t j = 0; j < names.size(); ++j) {
3037f47549516ae5938759b5c834c8423378a60b3d8Andy Hung            mixer->setParameter(names[j], AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
304e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                    (char *) outputAddr + i * outputFrameSize);
305e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            if (auxFilename) {
3067f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                mixer->setParameter(names[j], AudioMixer::TRACK, AudioMixer::AUX_BUFFER,
307e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung                        (char *) auxAddr + i * auxFrameSize);
308e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            }
309e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        }
310d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten        mixer->process();
311e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    }
312e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    outputFrames = i; // reset output frames to the data actually produced.
313e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
314e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    // write to files
315e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    writeFile(outputFilename, outputAddr,
316e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung            outputSampleRate, outputChannels, outputFrames, useMixerFloat);
317e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    if (auxFilename) {
318e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        // Aux buffer is always in q4_27 format for now.
319e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        // memcpy_to_i16_from_q4_27(), but with stereo frame count (not sample count)
320e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        ditherAndClamp((int32_t*)auxAddr, (int32_t*)auxAddr, outputFrames >> 1);
321e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung        writeFile(auxFilename, auxAddr, outputSampleRate, 1, outputFrames, false);
322e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    }
323e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung
324e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    delete mixer;
325e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    free(outputAddr);
326e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    free(auxAddr);
327e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung    return EXIT_SUCCESS;
328e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung}
329