]> git.mxchange.org Git - simgear.git/blob - simgear/sound/sample_openal.cxx
Rewrite the entire audio support library on top of OpenAL rather than plib's
[simgear.git] / simgear / sound / sample_openal.cxx
1 // sample.cxx -- Sound sample encapsulation class
2 // 
3 // Written by Curtis Olson, started April 2004.
4 //
5 // Copyright (C) 2004  Curtis L. Olson - curt@flightgear.org
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23
24 #include <AL/al.h>
25 #include <AL/alut.h>
26
27 #include <simgear/debug/logstream.hxx>
28 #include <simgear/misc/sg_path.hxx>
29 #include <simgear/structure/exception.hxx>
30
31 #include "sample_openal.hxx"
32
33
34 //
35 // SGSoundSample
36 //
37
38
39 static void print_openal_error( ALuint error ) {
40     if ( error == AL_INVALID_NAME ) {
41         SG_LOG( SG_GENERAL, SG_ALERT, "AL_INVALID_NAME" );
42     } else if ( error == AL_ILLEGAL_ENUM ) {
43         SG_LOG( SG_GENERAL, SG_ALERT, "AL_ILLEGAL_ENUM" );
44     } else if ( error == AL_INVALID_VALUE ) {
45         SG_LOG( SG_GENERAL, SG_ALERT, "AL_INVALID_VALUE" );
46     } else if ( error == AL_ILLEGAL_COMMAND ) {
47         SG_LOG( SG_GENERAL, SG_ALERT, "AL_ILLEGAL_COMMAND" );
48     } else if ( error == AL_OUT_OF_MEMORY ) {
49         SG_LOG( SG_GENERAL, SG_ALERT, "AL_OUT_OF_MEMORY" );
50     } else {
51         SG_LOG( SG_GENERAL, SG_ALERT, "Unhandled error code = " << error );
52     }
53 }
54
55
56 // constructor
57 SGSoundSample::SGSoundSample( const char *path, const char *file ) :
58     pitch(1.0),
59     volume(1.0),
60     loop(AL_FALSE)
61 {
62     SGPath samplepath( path );
63     if ( strlen(file) ) {
64         samplepath.append( file );
65     }
66      
67     SG_LOG( SG_GENERAL, SG_ALERT, "From file sounds sample = "
68             << samplepath.str() );
69
70     ALuint error;
71
72     source_pos[0] = 0.0; source_pos[1] = 0.0; source_pos[2] = 0.0;
73     source_vel[0] = 0.0; source_vel[1] = 0.0; source_vel[2] = 0.0;
74
75     // clear errors from elsewhere?
76     alGetError();
77
78     // create an OpenAL buffer handle
79     alGenBuffers(1, &buffer);
80     error = alGetError();
81     if ( error != AL_NO_ERROR ) {
82         print_openal_error( error );
83         throw sg_exception("Failed to gen OpenAL buffer.");
84     } else {
85         SG_LOG( SG_GENERAL, SG_ALERT, "Buffer created ok!" );
86     }
87
88     // Load the sample file
89     alutLoadWAVFile( (ALbyte *)samplepath.c_str(),
90                      &format, &data, &size, &freq, &loop );
91     if (alGetError() != AL_NO_ERROR) {
92         throw sg_exception("Failed to load wav file.");
93     }
94
95     // Copy data to the internal OpenAL buffer
96     alBufferData( buffer, format, data, size, freq );
97     if (alGetError() != AL_NO_ERROR) {
98         throw sg_exception("Failed to buffer data.");
99     }
100
101     alutUnloadWAV( format, data, size, freq );
102
103     // Bind buffer with a source.
104     alGenSources(1, &source);
105     if (alGetError() != AL_NO_ERROR) {
106         throw sg_exception("Failed to gen source.");
107     }
108
109     alSourcei( source, AL_BUFFER, buffer );
110     alSourcef( source, AL_PITCH, pitch );
111     alSourcef( source, AL_GAIN, volume );
112     alSourcefv( source, AL_POSITION, source_pos );
113     alSourcefv( source, AL_VELOCITY, source_vel );
114     alSourcei( source, AL_LOOPING, loop );
115 }
116
117
118 // constructor
119 SGSoundSample::SGSoundSample( unsigned char *_data, int len, int _freq ) :
120     pitch(1.0),
121     volume(1.0),
122     loop(AL_FALSE)
123 {
124     SG_LOG( SG_GENERAL, SG_ALERT, "In memory sounds sample" );
125
126     source_pos[0] = 0.0; source_pos[1] = 0.0; source_pos[2] = 0.0;
127     source_vel[0] = 0.0; source_vel[1] = 0.0; source_vel[2] = 0.0;
128
129     // Load wav data into a buffer.
130     alGenBuffers(1, &buffer);
131     if (alGetError() != AL_NO_ERROR) {
132         SG_LOG( SG_GENERAL, SG_ALERT, "Error in alGenBuffers()" );
133         return;
134     }
135
136     format = AL_FORMAT_MONO8;
137     size = len;
138     data = _data;
139     freq = _freq;
140
141     alBufferData( buffer, format, data, size, freq );
142
143     // Bind buffer with a source.
144     alGenSources(1, &source);
145     if (alGetError() != AL_NO_ERROR) {
146         throw sg_exception("Failed to gen source.");
147     }
148
149     alSourcei( source, AL_BUFFER, buffer );
150     alSourcef( source, AL_PITCH, pitch );
151     alSourcef( source, AL_GAIN, volume );
152     alSourcefv( source, AL_POSITION, source_pos );
153     alSourcefv( source, AL_VELOCITY, source_vel );
154     alSourcei( source, AL_LOOPING, loop );
155 }
156
157
158 // destructor
159 SGSoundSample::~SGSoundSample() {
160     SG_LOG( SG_GENERAL, SG_ALERT, "Deleting a sample" );
161     alDeleteSources(1, &source);
162     alDeleteBuffers(1, &buffer);
163 }
164
165
166 // play the sample
167 void SGSoundSample::play( bool _loop ) {
168     loop = _loop;
169     
170     // make sure sound isn't already playing
171     alSourceStop( source );
172
173     alSourcei( source, AL_LOOPING, loop );
174     alSourcePlay( source );
175 }
176
177
178 // stop playing the sample
179 void SGSoundSample::stop() {
180     alSourceStop( source );
181 }