]> git.mxchange.org Git - flightgear.git/blob - src/Sound/soundmgr.cxx
1. Tidies up h-FOV/v-FOV handling and makes window scale depend on
[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     if ( audio_sched->notWorking() ) {
68         SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
69     } else {
70         audio_sched -> setMaxConcurrent ( 6 ); 
71
72         audio_mixer = new smMixer;
73
74         SG_LOG( SG_GENERAL, SG_INFO,
75                 "Rate = " << audio_sched->getRate()
76                 << "  Bps = " << audio_sched->getBps()
77                 << "  Stereo = " << audio_sched->getStereo() );
78     }
79 }
80
81 // destructor
82
83 FGSoundMgr::~FGSoundMgr() {
84     sound_map_iterator current = sounds.begin();
85     sound_map_iterator end = sounds.end();
86     for ( ; current != end; ++current ) {
87         FGSimpleSound *s = current->second;
88         delete s->get_sample();
89         delete s;
90     }
91
92     delete audio_sched;
93     delete audio_mixer;
94 }
95
96
97 // initialize the sound manager
98 void FGSoundMgr::init() {
99     last.stamp();
100     safety = FG_MAX_SOUND_SAFETY;
101
102     // audio_mixer -> setMasterVolume ( 80 ) ;  /* 80% of max volume. */
103     audio_sched -> setSafetyMargin ( FG_SOUND_SAFETY_MULT * safety ) ;
104
105     sound_map_iterator current = sounds.begin();
106     sound_map_iterator end = sounds.end();
107     for ( ; current != end; ++current ) {
108         FGSimpleSound *s = current->second;
109         delete s->get_sample();
110         delete s;
111     }
112     sounds.clear();
113
114 }
115
116 void FGSoundMgr::bind ()
117 {
118   // no properties yet
119 }
120
121 void FGSoundMgr::unbind ()
122 {
123   // no properties yet
124 }
125
126
127 // run the audio scheduler
128 void FGSoundMgr::update(int dt) {
129     SGTimeStamp current;
130     current.stamp();
131
132     double elapsed = (double)(current - last) / 1000000.0;
133     last = current;
134
135     if ( elapsed > safety ) {
136         safety = elapsed;
137     } else {
138         safety = safety * 0.99 + elapsed * 0.01;
139     }
140     if ( safety > FG_MAX_SOUND_SAFETY ) {
141         safety = FG_MAX_SOUND_SAFETY;
142     }
143     // cout << "safety = " << safety << endl;
144     audio_sched -> setSafetyMargin ( FG_SOUND_SAFETY_MULT * safety ) ;
145
146     if ( !audio_sched->not_working() )
147         audio_sched -> update();
148 }
149
150
151 // add a sound effect, return true if successful
152 bool FGSoundMgr::add( FGSimpleSound *sound, const string& refname  ) {
153     sounds[refname] = sound;
154
155     return true;
156 }
157
158
159 // remove a sound effect, return true if successful
160 bool FGSoundMgr::remove( const string& refname ) {
161
162     sound_map_iterator it = sounds.find( refname );
163     if ( it != sounds.end() ) {
164         // first stop the sound from playing (so we don't bomb the
165         // audio scheduler)
166         FGSimpleSound *sample = it->second;
167
168         // cout << "Playing " << sample->get_sample()->getPlayCount()
169         //      << " instances!" << endl;
170
171         audio_sched->stopSample( sample->get_sample() );
172         audio_sched->addSampleEnvelope( sample->get_sample(), 0, 0, 
173                                         NULL,
174                                         SL_PITCH_ENVELOPE );
175         audio_sched->addSampleEnvelope( sample->get_sample(), 0, 1, 
176                                         NULL,
177                                         SL_VOLUME_ENVELOPE );
178
179         // must call audio_sched->update() after stopping the sound
180         // but before deleting it.
181         audio_sched -> update();
182         // cout << "Still playing " << sample->get_sample()->getPlayCount()
183         //      << " instances!" << endl;
184
185         delete sample;
186         sounds.erase( it );
187
188         return true;
189    } else {
190         return false;
191     }
192 }
193
194
195 // return true of the specified sound exists in the sound manager system
196 bool FGSoundMgr::exists( const string& refname ) {
197     sound_map_iterator it = sounds.find( refname );
198     if ( it != sounds.end() ) {
199         return true;
200    } else {
201         return false;
202     }
203 }
204
205
206 // return a pointer to the FGSimpleSound if the specified sound exists
207 // in the sound manager system, otherwise return NULL
208 FGSimpleSound *FGSoundMgr::find( const string& refname ) {
209     sound_map_iterator it = sounds.find( refname );
210     if ( it != sounds.end() ) {
211         return it->second;
212    } else {
213         return NULL;
214     }
215 }
216
217
218 // tell the scheduler to play the indexed sample in a continuous
219 // loop
220 bool FGSoundMgr::play_looped( const string& refname ) {
221     sound_map_iterator it = sounds.find( refname );
222     if ( it != sounds.end() ) {
223         FGSimpleSound *sample = it->second;
224         audio_sched->loopSample( sample->get_sample() );
225         audio_sched->addSampleEnvelope( sample->get_sample(), 0, 0, 
226                                         sample->get_pitch_envelope(),
227                                         SL_PITCH_ENVELOPE );
228         audio_sched->addSampleEnvelope( sample->get_sample(), 0, 1, 
229                                         sample->get_volume_envelope(),
230                                         SL_VOLUME_ENVELOPE );
231         
232         return true;
233     } else {
234         return false;
235     }
236 }
237
238
239 // tell the scheduler to play the indexed sample once
240 bool FGSoundMgr::play_once( const string& refname ) {
241     sound_map_iterator it = sounds.find( refname );
242     if ( it != sounds.end() ) {
243         FGSimpleSound *sample = it->second;
244         audio_sched->stopSample( sample->get_sample() );
245         audio_sched->playSample( sample->get_sample() );
246         audio_sched->addSampleEnvelope( sample->get_sample(), 0, 0, 
247                                         sample->get_pitch_envelope(),
248                                         SL_PITCH_ENVELOPE );
249         audio_sched->addSampleEnvelope( sample->get_sample(), 0, 1, 
250                                         sample->get_volume_envelope(),
251                                         SL_VOLUME_ENVELOPE );
252         
253         return true;
254     } else {
255         return false;
256     }
257 }
258
259
260 // return true of the specified sound is currently being played
261 bool FGSoundMgr::is_playing( const string& refname ) {
262     sound_map_iterator it = sounds.find( refname );
263     if ( it != sounds.end() ) {
264         FGSimpleSound *sample = it->second;
265         return (sample->get_sample()->getPlayCount() > 0 );
266         return true;
267     } else {
268         return false;
269     }
270 }
271
272
273 // immediate stop playing the sound
274 bool FGSoundMgr::stop( const string& refname ) {
275     sound_map_iterator it = sounds.find( refname );
276     if ( it != sounds.end() ) {
277         FGSimpleSound *sample = it->second;
278         audio_sched->stopSample( sample->get_sample() );
279         return true;
280     } else {
281         return false;
282     }
283 }