test-mixer.cpp revision d79072e9dff59f767cce2cda1caab80ce5a0815b
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> 24e4fc42359cdd9786e521054a3a0491d6bc3a9e1cAndy Hung#include "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