reverb.c revision c2303eb5497c488db786dcb2b8514db229452536
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// Demonstrate environmental reverb and preset reverb on an output mix and audio player
18
19#include "SLES/OpenSLES.h"
20#include <assert.h>
21#include <string.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <unistd.h>
25
26// Table of I3DL2 named environmental reverb settings
27
28typedef struct {
29    const char *mName;
30    SLEnvironmentalReverbSettings mSettings;
31} Pair;
32
33#define _(name) {#name, SL_I3DL2_ENVIRONMENT_PRESET_##name},
34
35Pair pairs[] = {
36    _(DEFAULT)
37    _(GENERIC)
38    _(PADDEDCELL)
39    _(ROOM)
40    _(BATHROOM)
41    _(LIVINGROOM)
42    _(STONEROOM)
43    _(AUDITORIUM)
44    _(CONCERTHALL)
45    _(CAVE)
46    _(ARENA)
47    _(HANGAR)
48    _(CARPETEDHALLWAY)
49    _(HALLWAY)
50    _(STONECORRIDOR)
51    _(ALLEY)
52    _(FOREST)
53    _(CITY)
54    _(MOUNTAINS)
55    _(QUARRY)
56    _(PLAIN)
57    _(PARKINGLOT)
58    _(SEWERPIPE)
59    _(UNDERWATER)
60    _(SMALLROOM)
61    _(MEDIUMROOM)
62    _(LARGEROOM)
63    _(MEDIUMHALL)
64    _(LARGEHALL)
65    _(PLATE)
66};
67
68// Reverb parameters for output mix
69SLuint16 mixPresetNumber = ~0;
70char *mixEnvName = NULL;
71SLEnvironmentalReverbSettings mixEnvSettings;
72
73// Reverb parameters for audio player
74SLuint16 playerPreset = ~0;
75char *playerName = NULL;
76SLEnvironmentalReverbSettings playerSettings;
77
78// Compare two environmental reverb settings structures.
79// Returns true if the settings are identical, or false if they are different.
80
81#define bool int
82bool slesutCompareEnvronmentalReverbSettings(
83        const SLEnvironmentalReverbSettings *settings1,
84        const SLEnvironmentalReverbSettings *settings2)
85{
86    return
87        (settings1->roomLevel == settings2->roomLevel) &&
88        (settings1->roomHFLevel == settings2->roomHFLevel) &&
89        (settings1->decayTime == settings2->decayTime) &&
90        (settings1->decayHFRatio == settings2->decayHFRatio) &&
91        (settings1->reflectionsLevel == settings2->reflectionsLevel) &&
92        (settings1->reflectionsDelay == settings2->reflectionsDelay) &&
93        (settings1->reverbLevel == settings2->reverbLevel) &&
94        (settings1->reverbDelay == settings2->reverbDelay) &&
95        (settings1->diffusion == settings2->diffusion) &&
96        (settings1->density == settings2->density);
97}
98
99// Print an environmental reverb settings structure.
100
101void slesutPrintEnvironmentalReverbSettings( const SLEnvironmentalReverbSettings *settings)
102{
103    printf("roomLevel: %u\n", settings->roomLevel);
104    printf("roomHFLevel: %u\n", settings->roomHFLevel);
105    printf("decayTime: %lu\n", settings->decayTime);
106    printf("decayHFRatio: %u\n", settings->decayHFRatio);
107    printf("reflectionsLevel: %u\n", settings->reflectionsLevel);
108    printf("reflectionsDelay: %lu\n", settings->reflectionsDelay);
109    printf("reverbLevel: %u\n", settings->reverbLevel);
110    printf("reverbDelay: %lu\n", settings->reverbDelay);
111    printf("diffusion: %u\n", settings->diffusion);
112    printf("density: %u\n", settings->density);
113}
114
115// Main program
116
117int main(int argc, char **argv)
118{
119    SLresult result;
120
121    // process command line parameters
122    char *prog = argv[0];
123    int i;
124    for (i = 1; i < argc; ++i) {
125        char *arg = argv[i];
126        if (arg[0] != '-')
127            break;
128        if (!strncmp(arg, "--mix-preset=", 13)) {
129            mixPresetNumber = atoi(&arg[13]);
130        } else if (!strncmp(arg, "--mix-name=", 11)) {
131            mixEnvName = &arg[11];
132        } else {
133            fprintf(stderr, "%s: unknown option %s ignored\n", prog, arg);
134        }
135    }
136    if (argc - i != 1) {
137        fprintf(stderr, "usage: %s --mix-preset=# --mix-name=name filename\n", prog);
138        exit(EXIT_FAILURE);
139    }
140    char *pathname = argv[i];
141
142    if (NULL != mixEnvName) {
143        unsigned j;
144        for (j = 0; j < sizeof(pairs) / sizeof(pairs[0]); ++j) {
145            //printf("comparing %s %s\n", mixEnvName, pairs[j].mName);
146            if (!strcasecmp(mixEnvName, pairs[j].mName)) {
147                mixEnvSettings = pairs[j].mSettings;
148                goto found;
149            }
150        }
151        fprintf(stderr, "%s: reverb name %s not found\n", prog, mixEnvName);
152        exit(EXIT_FAILURE);
153found:
154        printf("Using reverb name %s\n", mixEnvName);
155    }
156
157    // create engine
158    SLObjectItf engineObject;
159    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
160    assert(SL_RESULT_SUCCESS == result);
161    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
162    assert(SL_RESULT_SUCCESS == result);
163    SLEngineItf engineEngine;
164    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
165    assert(SL_RESULT_SUCCESS == result);
166
167    // create output mix
168    SLInterfaceID mix_ids[2];
169    SLboolean mix_req[2];
170    SLuint32 count = 0;
171    if (mixPresetNumber != ((SLuint16) ~0)) {
172        mix_req[count] = SL_BOOLEAN_TRUE;
173        mix_ids[count++] = SL_IID_PRESETREVERB;
174    }
175    if (mixEnvName != NULL) {
176        mix_req[count] = SL_BOOLEAN_TRUE;
177        mix_ids[count++] = SL_IID_ENVIRONMENTALREVERB;
178    }
179    SLObjectItf mixObject;
180    result = (*engineEngine)->CreateOutputMix(engineEngine, &mixObject, count, mix_ids, mix_req);
181    assert(SL_RESULT_SUCCESS == result);
182    result = (*mixObject)->Realize(mixObject, SL_BOOLEAN_FALSE);
183    assert(SL_RESULT_SUCCESS == result);
184
185    // configure preset reverb on output mix
186    SLPresetReverbItf mixPresetReverb;
187    if (mixPresetNumber != ((SLuint16) ~0)) {
188        result = (*mixObject)->GetInterface(mixObject, SL_IID_PRESETREVERB, &mixPresetReverb);
189        assert(SL_RESULT_SUCCESS == result);
190        SLuint16 getPresetReverb = 12345;
191        result = (*mixPresetReverb)->GetPreset(mixPresetReverb, &getPresetReverb);
192        assert(SL_RESULT_SUCCESS == result);
193        printf("Output mix default preset reverb %u\n", getPresetReverb);
194        result = (*mixPresetReverb)->SetPreset(mixPresetReverb, mixPresetNumber);
195        if (SL_RESULT_SUCCESS == result) {
196            result = (*mixPresetReverb)->GetPreset(mixPresetReverb, &getPresetReverb);
197            assert(SL_RESULT_SUCCESS == result);
198            assert(getPresetReverb == mixPresetNumber);
199            printf("output mix preset reverb successfully changed to %u\n", mixPresetNumber);
200        } else
201            printf("Unable to set preset reverb to %u, result=%lu\n", mixPresetNumber, result);
202    }
203
204    // configure environmental reverb on output mix
205    SLEnvironmentalReverbItf mixEnvironmentalReverb;
206    if (mixEnvName != NULL) {
207        result = (*mixObject)->GetInterface(mixObject, SL_IID_ENVIRONMENTALREVERB,
208                &mixEnvironmentalReverb);
209        assert(SL_RESULT_SUCCESS == result);
210        SLEnvironmentalReverbSettings getSettings;
211        result = (*mixEnvironmentalReverb)->GetEnvironmentalReverbProperties(mixEnvironmentalReverb,
212                &getSettings);
213        assert(SL_RESULT_SUCCESS == result);
214        printf("Output mix default environmental reverb settings\n");
215        printf("------------------------------------------------\n");
216        slesutPrintEnvironmentalReverbSettings(&getSettings);
217        printf("\n");
218        result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb,
219                &mixEnvSettings);
220        assert(SL_RESULT_SUCCESS == result);
221        printf("Output mix new environmental reverb settings\n");
222        printf("--------------------------------------------\n");
223        slesutPrintEnvironmentalReverbSettings(&mixEnvSettings);
224        printf("\n");
225        result = (*mixEnvironmentalReverb)->GetEnvironmentalReverbProperties(mixEnvironmentalReverb,
226                &getSettings);
227        assert(SL_RESULT_SUCCESS == result);
228        printf("Output mix read environmental reverb settings\n");
229        printf("--------------------------------------------\n");
230        slesutPrintEnvironmentalReverbSettings(&getSettings);
231        printf("\n");
232        // assert(slesutCompareEnvronmentalReverbSettings(&getSettings, &mixEnvSettings));
233    }
234
235    // create audio player
236    SLDataLocator_URI locURI = {SL_DATALOCATOR_URI, pathname};
237    SLDataFormat_MIME dfMIME = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
238    SLDataSource audioSrc = {&locURI, &dfMIME};
239    SLDataLocator_OutputMix locOutputMix = {SL_DATALOCATOR_OUTPUTMIX, mixObject};
240    SLDataSink audioSnk = {&locOutputMix, NULL};
241    SLInterfaceID player_ids[3];
242    SLboolean player_req[3];
243    count = 0;
244    if (playerPreset != ((SLuint16) ~0)) {
245        player_req[count] = SL_BOOLEAN_TRUE;
246        player_ids[count++] = SL_IID_PRESETREVERB;
247    }
248    if (playerName != NULL) {
249        player_req[count] = SL_BOOLEAN_TRUE;
250        player_ids[count++] = SL_IID_ENVIRONMENTALREVERB;
251    }
252    if (mixPresetNumber != ((SLuint16) ~0) || mixEnvName != NULL) {
253        player_req[count] = SL_BOOLEAN_TRUE;
254        player_ids[count++] = SL_IID_EFFECTSEND;
255    }
256    SLObjectItf playerObject;
257    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc,
258        &audioSnk, count, player_ids, player_req);
259    assert(SL_RESULT_SUCCESS == result);
260    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
261    SLPlayItf playerPlay;
262    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
263    assert(SL_RESULT_SUCCESS == result);
264
265    // get duration
266    SLmillisecond duration;
267    result = (*playerPlay)->GetDuration(playerPlay, &duration);
268    assert(SL_RESULT_SUCCESS == result);
269    if (SL_TIME_UNKNOWN == duration)
270        printf("first attempt at duration: unknown\n");
271    else
272        printf("first attempt at duration: %.1f seconds\n", duration / 1000.0);
273
274    // set play state to paused to enable pre-fetch so we can get a more reliable duration
275    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PAUSED);
276    assert(SL_RESULT_SUCCESS == result);
277    usleep(1000000);
278    result = (*playerPlay)->GetDuration(playerPlay, &duration);
279    assert(SL_RESULT_SUCCESS == result);
280    if (SL_TIME_UNKNOWN == duration)
281        printf("second attempt at duration: unknown\n");
282    else
283        printf("second attempt at duration: %.1f seconds\n", duration / 1000.0);
284
285    // if reverb is on output mix (aux effect), then enable it
286    if (mixPresetNumber != ((SLuint16) ~0) || mixEnvName != NULL) {
287        SLEffectSendItf playerEffectSend;
288        result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend);
289        assert(SL_RESULT_SUCCESS == result);
290        if (mixPresetNumber != ((SLuint16) ~0)) {
291            result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixPresetReverb,
292                    SL_BOOLEAN_TRUE, (SLmillibel) 0);
293            assert(SL_RESULT_SUCCESS == result);
294        }
295        if (mixEnvName != NULL) {
296            result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb,
297                    SL_BOOLEAN_TRUE, (SLmillibel) 0);
298            assert(SL_RESULT_SUCCESS == result);
299        }
300    }
301
302    // start audio playing
303    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
304    assert(SL_RESULT_SUCCESS == result);
305
306    // wait for audio to finish playing
307    SLuint32 state;
308    for (;;) {
309        result = (*playerPlay)->GetPlayState(playerPlay, &state);
310        assert(SL_RESULT_SUCCESS == result);
311        if (SL_PLAYSTATE_PLAYING != state)
312            break;
313        usleep(5000000);
314     }
315    assert(SL_PLAYSTATE_PAUSED == state);
316
317    return EXIT_SUCCESS;
318}
319