summaryrefslogtreecommitdiffstats
path: root/src/java/demos/efx/EFXFilter.java
blob: 94bcdea3abac505cef953899e6087d5eb5443c81 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
package demos.efx;

import com.jogamp.openal.AL;
import com.jogamp.openal.ALC;
import com.jogamp.openal.ALCcontext;
import com.jogamp.openal.ALCdevice;
import com.jogamp.openal.ALExt;
import com.jogamp.openal.ALFactory;
import com.jogamp.openal.util.WAVData;
import com.jogamp.openal.util.WAVLoader;

/**
 * OpenAL 1.1 EFX test class, a translation of the C++ EFXFilter demo from the
 * OpenAL 1.1 SDK.
 * 
 * @author Emanuel Rabina
 */
public class EFXFilter {

    private static ALCdevice device;
    private static ALCcontext context;
    private static ALC alc;
    private static AL al;
    private static ALExt alExt;

    private static String wavefile = "demos/data/Footsteps.wav";

    /**
     * Run something similar to the EFXFilter sample from the OpenAL 1.1
     * (w/ EFX) SDK.
     * 
     * @param args
     */
    public static void main(String[] args) {

        try {
            initOpenAL();

            // Requires EFX support
            if (alc.alcIsExtensionPresent(device, "ALC_EXT_EFX")) {

                // Load the sound sample to a buffer
                WAVData wavedata = WAVLoader.loadFromStream(EFXFilter.class.getClassLoader().getResourceAsStream(wavefile));
                int[] buffers = new int[1];
                al.alGenBuffers(1, buffers, 0);
                al.alBufferData(buffers[0], wavedata.format, wavedata.data, wavedata.size, wavedata.freq);
                int buffer = buffers[0];

                // Attach buffer to a source
                int[] sources = new int[1];
                al.alGenSources(1, sources, 0);
                al.alSourcei(sources[0], AL.AL_BUFFER, buffer);
                int source = sources[0];

                // Play the sound through a variety of EFX filters & effects
                playDry(source);
                playDirectFilter(source);
                playAuxiliaryNoFilter(source);
                playAuxiliaryFilter(source);

                // Cleanup buffer & source
                al.alSourcei(source, AL.AL_BUFFER, 0);
                al.alDeleteSources(1, new int[]{ source }, 0);
                al.alDeleteBuffers(1, new int[]{ buffer }, 0);
            }
            else {
                System.out.println("EFX not supported.");
            }

            shutdownOpenAL();
            System.exit(0);
        }
        catch (Exception ex) {
            System.out.println(ex.getMessage());
            ex.printStackTrace();
            System.exit(1);
        }
    }

    /**
     * Set up an OpenAL context and make it current on this thread.
     */
    private static void initOpenAL() {

        alc = ALFactory.getALC();
        device = alc.alcOpenDevice(null);
        context = alc.alcCreateContext(device, null);
        alc.alcMakeContextCurrent(context);

        al = ALFactory.getAL();
        alExt = ALFactory.getALExt();
    }

    /**
     * Release & destroy the OpenAL context and close the device.
     */
    private static void shutdownOpenAL() {

        alc.alcMakeContextCurrent(null);
        alc.alcDestroyContext(context);
        alc.alcCloseDevice(device);

        alc = null;
        al = null;
    }

    /**
     * Plays the source without any filters.
     * 
     * @param source Source ID.
     */
    private static void playDry(int source) {

        System.out.println("Source played dry");
        play(source);
    }

    /**
     * Plays the source with a low-pass filter.
     * 
     * @param source Source ID.
     */
    private static void playDirectFilter(int source) {

        System.out.println("Source played through a direct lowpass filter");

        // Attach a lowpass filter to the source
        int filter = createFilter(ALExt.AL_FILTER_LOWPASS, 1f, 0.5f);
        al.alSourcei(source, ALExt.AL_DIRECT_FILTER, filter);

        play(source);

        // Cleanup
        al.alSourcei(source, ALExt.AL_DIRECT_FILTER, ALExt.AL_FILTER_NULL);
        deleteFilter(filter);
    }

    /**
     * Plays the source through an auxiliary reverb with no filter.
     * 
     * @param source Source ID.
     */
    private static void playAuxiliaryNoFilter(int source) {

        System.out.println("Source played through an auxiliary reverb without filtering");

        // Create auxiliary effect slots & effects
        int[] effectslots = new int[1];
        alExt.alGenAuxiliaryEffectSlots(1, effectslots, 0);
        int[] effects = new int[1];
        alExt.alGenEffects(1, effects, 0);

        // Configure the effect to be a reverb, load it to the effect slot
        alExt.alEffecti(effects[0], ALExt.AL_EFFECT_TYPE, ALExt.AL_EFFECT_REVERB);
        alExt.alAuxiliaryEffectSloti(effectslots[0], ALExt.AL_EFFECTSLOT_EFFECT, effects[0]);

        // Enable Send 0 from the Source to the Auxiliary Effect Slot without filtering
        al.alSource3i(source, ALExt.AL_AUXILIARY_SEND_FILTER, effectslots[0], 0, ALExt.AL_FILTER_NULL);

        play(source);

        // Cleanup
        al.alSource3i(source, ALExt.AL_AUXILIARY_SEND_FILTER, ALExt.AL_EFFECTSLOT_NULL, 0, ALExt.AL_FILTER_NULL);
        alExt.alDeleteAuxiliaryEffectSlots(1, effectslots, 0);
        alExt.alDeleteEffects(1, effects, 0);
    }

    /**
     * Plays the source through an auxiliary reverb with a low-pass filter.
     * 
     * @param source SourceID.
     */
    private static void playAuxiliaryFilter(int source) {

        System.out.println("Source played through an auxiliary reverb with lowpass filter");

        // Create a lowpass filter, attach it to a reverb effect
        int filter = createFilter(ALExt.AL_FILTER_LOWPASS, 1f, 0.5f);

        int[] effectslots = new int[1];
        alExt.alGenAuxiliaryEffectSlots(1, effectslots, 0);
        int[] effects = new int[1];
        alExt.alGenEffects(1, effects, 0);
        alExt.alEffecti(effects[0], ALExt.AL_EFFECT_TYPE, ALExt.AL_EFFECT_REVERB);
        alExt.alAuxiliaryEffectSloti(effectslots[0], ALExt.AL_EFFECTSLOT_EFFECT, effects[0]);

        // Enable Send 0 from the Source to the Auxiliary Effect Slot with filtering
        al.alSource3i(source, ALExt.AL_AUXILIARY_SEND_FILTER, effectslots[0], 0, filter);

        play(source);

        // Cleanup
        al.alSource3i(source, ALExt.AL_AUXILIARY_SEND_FILTER, ALExt.AL_EFFECTSLOT_NULL, 0, ALExt.AL_FILTER_NULL);
        alExt.alDeleteAuxiliaryEffectSlots(1, effectslots, 0);
        alExt.alDeleteEffects(1, effects, 0);
    }

    /**
     * Plays the source, returning once the source has been completed.
     * 
     * @param source Source ID.
     */
    private static void play(int source) {

        al.alSourcePlay(source);

        while (true) {
            int[] state = new int[1];
            al.alGetSourcei(source, AL.AL_SOURCE_STATE, state, 0);

            if (state[0] == AL.AL_PLAYING) {
                try {
                    Thread.sleep(50);
                }
                catch (InterruptedException iex) {
                    throw new RuntimeException(iex.getMessage(), iex);
                }
            }
            else {
                break;
            }
        }
    }

    /**
     * Creates a new OpenAL EFX filter per the given specs.
     * 
     * @param filtertype Type of filter to create.  One of {@link AL#AL_FILTER_LOWPASS},
     * 					 or {@link AL#AL_FILTER_HIGHPASS}.
     * @param gain		 Filter gain.
     * @param gainlimit	 Filter frequency (upper/lower) limit.
     * @return Filter ID.
     */
    private static int createFilter(int filtertype, float gain, float gainlimit) {

        int filters[] = new int[1];
        alExt.alGenFilters(1, filters, 0);

        alExt.alFilteri(filters[0], ALExt.AL_FILTER_TYPE, filtertype);
        alExt.alFilterf(filters[0], filtertype, gain);
        alExt.alFilterf(filters[0], filtertype, gainlimit);

        return filters[0];
    }

    /**
     * Deletes the given OpenAL EFX filter.
     * 
     * @param filter Filter ID.
     */
    private static void deleteFilter(int filter) {

        alExt.alDeleteFilters(1, new int[]{ filter }, 0);
    }
}