]> git.mxchange.org Git - flightgear.git/blob - src/Sound/soundmgr.cxx
Removed old remnants of plib-1.2.x support. We haven't officially supported
[flightgear.git] / src / Sound / soundmgr.cxx
1 // soundmgr.cxx -- Sound effect management class
2 //
3 // Sound manager initially written by David Findlay
4 // <david_j_findlay@yahoo.com.au> 2001
5 //
6 // C++-ified by Curtis Olson, started March 2001.
7 //
8 // Copyright (C) 2001  Curtis L. Olson - curt@flightgear.org
9 //
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License as
12 // published by the Free Software Foundation; either version 2 of the
13 // License, or (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 // General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 //
24 // $Id$
25
26
27 #include <simgear/debug/logstream.hxx>
28 #include <simgear/misc/sg_path.hxx>
29
30 #include <Main/globals.hxx>
31
32 #include "soundmgr.hxx"
33
34 #define FG_SOUND_SAFETY_MULT 3
35 #define FG_MAX_SOUND_SAFETY ( 1.0 / FG_SOUND_SAFETY_MULT )
36
37 // constructor
38 FGSimpleSound::FGSimpleSound( string file ) {
39     SGPath slfile( globals->get_fg_root() );
40     slfile.append( file );
41     sample = new slSample ( (char *)slfile.c_str() );
42     pitch_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
43     volume_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
44     pitch_envelope->setStep ( 0, 0.01, 1.0 );
45     volume_envelope->setStep ( 0, 0.01, 1.0 );
46 }
47
48 FGSimpleSound::FGSimpleSound( unsigned char *buffer, int len ) {
49     sample = new slSample ( buffer, len );
50     pitch_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
51     volume_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
52     pitch_envelope->setStep ( 0, 0.01, 1.0 );
53     volume_envelope->setStep ( 0, 0.01, 1.0 );
54 }
55
56 // destructor
57 FGSimpleSound::~FGSimpleSound() {
58     delete pitch_envelope;
59     delete volume_envelope;
60     delete sample;
61 }
62
63
64 // constructor
65 FGSoundMgr::FGSoundMgr() {
66     audio_sched = new slScheduler( 8000 );
67     audio_sched -> setMaxConcurrent ( 6 ); 
68
69     audio_mixer = new smMixer;
70
71     SG_LOG( SG_GENERAL, SG_INFO,
72             "Rate = " << audio_sched->getRate()
73             << "  Bps = " << audio_sched->getBps()
74             << "  Stereo = " << audio_sched->getStereo() );
75 }
76
77 // destructor
78
79 FGSoundMgr::~FGSoundMgr() {
80     sound_map_iterator current = sounds.begin();
81     sound_map_iterator end = sounds.end();
82     for ( ; current != end; ++current ) {
83         FGSimpleSound *s = current->second;
84         delete s->get_sample();
85         delete s;
86     }
87
88     delete audio_sched;
89     delete audio_mixer;
90 }
91
92
93 // initialize the sound manager
94 void FGSoundMgr::init() {
95     last.stamp();
96     safety = FG_MAX_SOUND_SAFETY;
97
98     // audio_mixer -> setMasterVolume ( 80 ) ;  /* 80% of max volume. */
99     audio_sched -> setSafetyMargin ( FG_SOUND_SAFETY_MULT * safety ) ;
100
101     sound_map_iterator current = sounds.begin();
102     sound_map_iterator end = sounds.end();
103     for ( ; current != end; ++current ) {
104         FGSimpleSound *s = current->second;
105         delete s->get_sample();
106         delete s;
107     }
108     sounds.clear();
109
110 }
111
112 void FGSoundMgr::bind ()
113 {
114   // no properties yet
115 }
116
117 void FGSoundMgr::unbind ()
118 {
119   // no properties yet
120 }
121
122
123 // run the audio scheduler
124 void FGSoundMgr::update(int dt) {
125     SGTimeStamp current;
126     current.stamp();
127
128     double elapsed = (double)(current - last) / 1000000.0;
129     last = current;
130
131     if ( elapsed > safety ) {
132         safety = elapsed;
133     } else {
134         safety = safety * 0.99 + elapsed * 0.01;
135     }
136     if ( safety > FG_MAX_SOUND_SAFETY ) {
137         safety = FG_MAX_SOUND_SAFETY;
138     }
139     // cout << "safety = " << safety << endl;
140     audio_sched -> setSafetyMargin ( FG_SOUND_SAFETY_MULT * safety ) ;
141
142     if ( !audio_sched->not_working() )
143         audio_sched -> update();
144 }
145
146
147 // add a sound effect, return true if successful
148 bool FGSoundMgr::add( FGSimpleSound *sound, const string& refname  ) {
149     sounds[refname] = sound;
150
151     return true;
152 }
153
154
155 // remove a sound effect, return true if successful
156 bool FGSoundMgr::remove( const string& refname ) {
157
158     sound_map_iterator it = sounds.find( refname );
159     if ( it != sounds.end() ) {
160         // first stop the sound from playing (so we don't bomb the
161         // audio scheduler)
162         FGSimpleSound *sample = it->second;
163
164         // cout << "Playing " << sample->get_sample()->getPlayCount()
165         //      << " instances!" << endl;
166
167         audio_sched->stopSample( sample->get_sample() );
168         audio_sched->addSampleEnvelope( sample->get_sample(), 0, 0, 
169                                         NULL,
170                                         SL_PITCH_ENVELOPE );
171         audio_sched->addSampleEnvelope( sample->get_sample(), 0, 1, 
172                                         NULL,
173                                         SL_VOLUME_ENVELOPE );
174
175         // must call audio_sched->update() after stopping the sound
176         // but before deleting it.
177         audio_sched -> update();
178         // cout << "Still playing " << sample->get_sample()->getPlayCount()
179         //      << " instances!" << endl;
180
181         delete sample;
182         sounds.erase( it );
183
184         return true;
185    } else {
186         return false;
187     }
188 }
189
190
191 // return true of the specified sound exists in the sound manager system
192 bool FGSoundMgr::exists( const string& refname ) {
193     sound_map_iterator it = sounds.find( refname );
194     if ( it != sounds.end() ) {
195         return true;
196    } else {
197         return false;
198     }
199 }
200
201
202 // return a pointer to the FGSimpleSound if the specified sound exists
203 // in the sound manager system, otherwise return NULL
204 FGSimpleSound *FGSoundMgr::find( const string& refname ) {
205     sound_map_iterator it = sounds.find( refname );
206     if ( it != sounds.end() ) {
207         return it->second;
208    } else {
209         return NULL;
210     }
211 }
212
213
214 // tell the scheduler to play the indexed sample in a continuous
215 // loop
216 bool FGSoundMgr::play_looped( const string& refname ) {
217     sound_map_iterator it = sounds.find( refname );
218     if ( it != sounds.end() ) {
219         FGSimpleSound *sample = it->second;
220         audio_sched->loopSample( sample->get_sample() );
221         audio_sched->addSampleEnvelope( sample->get_sample(), 0, 0, 
222                                         sample->get_pitch_envelope(),
223                                         SL_PITCH_ENVELOPE );
224         audio_sched->addSampleEnvelope( sample->get_sample(), 0, 1, 
225                                         sample->get_volume_envelope(),
226                                         SL_VOLUME_ENVELOPE );
227         
228         return true;
229     } else {
230         return false;
231     }
232 }
233
234
235 // tell the scheduler to play the indexed sample once
236 bool FGSoundMgr::play_once( const string& refname ) {
237     sound_map_iterator it = sounds.find( refname );
238     if ( it != sounds.end() ) {
239         FGSimpleSound *sample = it->second;
240         audio_sched->stopSample( sample->get_sample() );
241         audio_sched->playSample( sample->get_sample() );
242         audio_sched->addSampleEnvelope( sample->get_sample(), 0, 0, 
243                                         sample->get_pitch_envelope(),
244                                         SL_PITCH_ENVELOPE );
245         audio_sched->addSampleEnvelope( sample->get_sample(), 0, 1, 
246                                         sample->get_volume_envelope(),
247                                         SL_VOLUME_ENVELOPE );
248         
249         return true;
250     } else {
251         return false;
252     }
253 }
254
255
256 // return true of the specified sound is currently being played
257 bool FGSoundMgr::is_playing( const string& refname ) {
258     sound_map_iterator it = sounds.find( refname );
259     if ( it != sounds.end() ) {
260         FGSimpleSound *sample = it->second;
261         return (sample->get_sample()->getPlayCount() > 0 );
262         return true;
263     } else {
264         return false;
265     }
266 }
267
268
269 // immediate stop playing the sound
270 bool FGSoundMgr::stop( const string& refname ) {
271     sound_map_iterator it = sounds.find( refname );
272     if ( it != sounds.end() ) {
273         FGSimpleSound *sample = it->second;
274         audio_sched->stopSample( sample->get_sample() );
275         return true;
276     } else {
277         return false;
278     }
279 }