# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\src\Main\soundmgr.cxx\r
+\r
+!IF "$(CFG)" == "FlightGear - Win32 Release"\r
+\r
+# PROP Intermediate_Dir "Release\main"\r
+\r
+!ELSEIF "$(CFG)" == "FlightGear - Win32 Debug"\r
+\r
+# PROP Intermediate_Dir "Debug\main"\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=.\src\Main\splash.cxx\r
\r
!IF "$(CFG)" == "FlightGear - Win32 Release"\r
fgfs.cxx fgfs.hxx \
globals.cxx globals.hxx \
keyboard.cxx keyboard.hxx \
- morse.cxx morse.hxx \
options.cxx options.hxx \
- soundmgr.cxx soundmgr.hxx \
splash.cxx splash.hxx \
viewer.cxx viewer.hxx \
viewer_lookat.cxx viewer_lookat.hxx \
$(top_builddir)/src/GUI/libGUI.a \
$(top_builddir)/src/Navaids/libNavaids.a \
$(top_builddir)/src/Scenery/libScenery.a \
+ $(top_builddir)/src/Sound/libSound.a \
$(top_builddir)/src/Airports/libAirports.a \
$(NETWORK_LIBS) \
$(top_builddir)/src/Objects/libObjects.a \
#include <simgear/timing/sg_time.hxx>
#include <simgear/misc/props.hxx>
-#include "soundmgr.hxx"
+#include <Sound/soundmgr.hxx>
#include "viewmgr.hxx"
FG_USING_STD( vector );
#endif
#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
+#ifdef ENABLE_AUDIO_SUPPORT
+# include <Sound/soundmgr.hxx>
+# include <Sound/morse.hxx>
+#endif
#include <Time/event.hxx>
#include <Time/fg_timer.hxx>
#include <Time/light.hxx>
#include "fg_io.hxx"
#include "globals.hxx"
#include "keyboard.hxx"
-#include "morse.hxx"
#include "splash.hxx"
-#ifdef ENABLE_AUDIO_SUPPORT
-# include "soundmgr.hxx"
-#endif
-
#ifdef macintosh
# include <console.h> // -dw- for command line dialog
#endif
// s2 = new FGSimpleSound( "Sounds/corflaps.wav" );
// s2->set_volume( 2.0 );
- FGMorse mmm;
- mmm.init();
- s2 = mmm.make_ident( "JLI" );
- globals->get_soundmgr()->add( s2, "flaps" );
+ // FGMorse mmm;
+ // mmm.init();
+ // s2 = mmm.make_ident( "JLI" );
+ // globals->get_soundmgr()->add( s2, "flaps" );
}
#endif
+++ /dev/null
-// morse.cxx -- Morse code generation class
-//
-// Written by Curtis Olson, started March 2001.
-//
-// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-//
-// $Id$
-
-
-#include "morse.hxx"
-
-
-// constructor
-FGMorse::FGMorse() {
-}
-
-// destructor
-FGMorse::~FGMorse() {
-}
-
-
-// allocate and initialize sound samples
-bool FGMorse::init() {
- int i, j;
-
- // Make DIT
- for ( i = 0; i < TRANSITION_BYTES; ++i ) {
- float level = ( sin( (double) i * 2.0 * M_PI / (8000.0 / FREQUENCY)) )
- * ((double)i / TRANSITION_BYTES) / 2.0 + 0.5;
-
- /* Convert to unsigned byte */
- dit[ i ] = (unsigned char) ( level * 255.0 ) ;
- }
-
- for ( i = TRANSITION_BYTES;
- i < DIT_SIZE - TRANSITION_BYTES - COUNT_SIZE; ++i ) {
- float level = ( sin( (double) i * 2.0 * M_PI / (8000.0 / FREQUENCY) ) )
- / 2.0 + 0.5;
-
- /* Convert to unsigned byte */
- dit[ i ] = (unsigned char) ( level * 255.0 ) ;
- }
- j = TRANSITION_BYTES;
- for ( i = DIT_SIZE - TRANSITION_BYTES - COUNT_SIZE;
- i < DIT_SIZE - COUNT_SIZE;
- ++i ) {
- float level = ( sin( (double) i * 2.0 * M_PI / (8000.0 / FREQUENCY) ) )
- * ((double)j / TRANSITION_BYTES) / 2.0 + 0.5;
- --j;
-
- /* Convert to unsigned byte */
- dit[ i ] = (unsigned char) ( level * 255.0 ) ;
- }
- for ( i = DIT_SIZE - COUNT_SIZE; i < DIT_SIZE; ++i ) {
- dit[ i ] = (unsigned char) ( 0.5 * 255.0 ) ;
- }
-
- // Make DAH
- for ( i = 0; i < TRANSITION_BYTES; ++i ) {
- float level = ( sin( (double) i * 2.0 * M_PI / (8000.0 / FREQUENCY) ) )
- * ((double)i / TRANSITION_BYTES) / 2.0 + 0.5;
-
- /* Convert to unsigned byte */
- dah[ i ] = (unsigned char) ( level * 255.0 ) ;
- }
-
- for ( i = TRANSITION_BYTES;
- i < DAH_SIZE - TRANSITION_BYTES - COUNT_SIZE;
- ++i ) {
- float level = ( sin( (double) i * 2.0 * M_PI / (8000.0 / FREQUENCY) ) )
- / 2.0 + 0.5;
-
- /* Convert to unsigned byte */
- dah[ i ] = (unsigned char) ( level * 255.0 ) ;
- }
- j = TRANSITION_BYTES;
- for ( int i = DAH_SIZE - TRANSITION_BYTES - COUNT_SIZE;
- i < DAH_SIZE - COUNT_SIZE;
- ++i ) {
- float level = ( sin( (double) i * 2.0 * M_PI / (8000.0 / FREQUENCY) ) )
- * ((double)j / TRANSITION_BYTES) / 2.0 + 0.5;
- --j;
-
- /* Convert to unsigned byte */
- dah[ i ] = (unsigned char) ( level * 255.0 ) ;
- }
- for ( int i = DAH_SIZE - COUNT_SIZE; i < DAH_SIZE; ++i ) {
- dah[ i ] = (unsigned char) ( 0.5 * 255.0 ) ;
- }
-
- // Make SPACE
- for ( int i = 0; i < SPACE_SIZE; ++i ) {
- space[ i ] = (unsigned char) ( 0.5 * 255 ) ;
- }
-
- return true;
-}
-
-
-// make a FGSimpleSound morse code transmission for the specified string
-FGSimpleSound *FGMorse::make_ident( const string& id ) {
- char *idptr = (char *)id.c_str();
-
- int length = 0;
- int i, j;
-
- // 1. Determine byte length of message
- for ( i = 0; i < (int)id.length(); ++i ) {
- if ( idptr[i] >= 'A' && idptr[i] <= 'Z' ) {
- char c = idptr[i] - 'A';
- for ( j = 0; j < 4 || alphabet[c][j] == end; ++j ) {
- if ( alphabet[c][j] == DIT ) {
- length += DIT_SIZE;
- } else if ( alphabet[c][j] == DAH ) {
- length += DAH_SIZE;
- }
- }
- length += SPACE_SIZE;
- } else {
- // skip unknown character
- }
- }
-
- // 2. Allocate space for the message
- unsigned char *buffer = new unsigned char[length];
-
- // 3. Assemble the message;
- unsigned char *bufptr = buffer;
-
- for ( i = 0; i < (int)id.length(); ++i ) {
- if ( idptr[i] >= 'A' && idptr[i] <= 'Z' ) {
- char c = idptr[i] - 'A';
- for ( j = 0; j < 4 || alphabet[c][j] == end; ++j ) {
- if ( alphabet[c][j] == DIT ) {
- memcpy( bufptr, dit, DIT_SIZE );
- bufptr += DIT_SIZE;
- } else if ( alphabet[c][j] == DAH ) {
- memcpy( bufptr, dah, DAH_SIZE );
- bufptr += DAH_SIZE;
- }
- }
- memcpy( bufptr, space, SPACE_SIZE );
- bufptr += SPACE_SIZE;
- } else {
- // skip unknown character
- }
- }
-
- // 4. create the simple sound and return
- FGSimpleSound *sample = new FGSimpleSound( buffer, length );
-
- return sample;
-}
+++ /dev/null
-// morse.hxx -- Morse code generation class
-//
-// Written by Curtis Olson, started March 2001.
-//
-// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-//
-// $Id$
-
-
-#ifndef _MORSE_HXX
-#define _MORSE_HXX
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <simgear/compiler.h>
-
-#include <plib/sl.h>
-#include <plib/sm.h>
-
-#include "soundmgr.hxx"
-
-
-// Quoting from http://www.kluft.com/~ikluft/ham/morse-intro.html by
-// Ian Kluft KO6YQ <ikluft@kluft.com>
-//
-// [begin quote]
-//
-// What is the Standard for Measuring Morse Code Speed?
-//
-// [This was adapted from the Ham Radio FAQ which used to be posted on UseNet.]
-//
-// The word PARIS was chosen as the standard length for CW code
-// speed. Each dit counts for one count, each dah counts for three
-// counts, intra-character spacing is one count, inter-character
-// spacing is three counts and inter-word spacing is seven counts, so
-// the word PARIS is exactly 50 counts:
-//
-// PPPPPPPPPPPPPP AAAAAA RRRRRRRRRR IIIIII SSSSSSSSSS
-// di da da di di da di da di di di di di di
-// 1 1 3 1 3 1 1 3 1 1 3 3 1 1 3 1 1 3 1 1 1 3 1 1 1 1 1 7 = 50
-// ^ ^ ^
-// ^Intra-character ^Inter-character Inter-word^
-//
-// So 5 words-per-minute = 250 counts-per-minute / 50 counts-per-word
-// or one count every 240 milliseconds. 13 words-per-minute is one
-// count every ~92.3 milliseconds. This method of sending code is
-// sometimes called "Slow Code", because at 5 wpm it sounds VERY SLOW.
-//
-// The "Farnsworth" method is accomplished by sending the dits and
-// dahs and intra-character spacing at a higher speed, then increasing
-// the inter-character and inter-word spacing to slow the sending
-// speed down to the desired speed. For example, to send at 5 wpm with
-// 13 wpm characters in Farnsworth method, the dits and
-// intra-character spacing would be 92.3 milliseconds, the dah would
-// be 276.9 milliseconds, the inter-character spacing would be 1.443
-// seconds and inter-word spacing would be 3.367 seconds.
-//
-// [end quote]
-
-// Ok, back to Curt
-
-// My formulation is based dit = 1 count, dah = 3 counts, 1 count for
-// intRA-character space, 3 counts for intER-character space. Target
-// is 5 wpm which by the above means 1 count = 240 milliseconds.
-//
-// AIM 1-1-7 (f) states that the frequency of the tone should be 1020
-// Hz for the VOR ident.
-
-
-static const char DI = '1';
-static const char DIT = '1';
-static const char DA = '2';
-static const char DAH = '2';
-static const char end = '0';
-
-static const int BYTES_PER_SECOND = 8000;
-static const int BEAT_LENGTH = 240; // milleseconds (5 wpm)
-static const int TRANSITION_BYTES = (int)(0.005 * BYTES_PER_SECOND);
-static const int COUNT_SIZE = BYTES_PER_SECOND * BEAT_LENGTH / 1000;
-static const int DIT_SIZE = 2 * COUNT_SIZE; // 2 counts
-static const int DAH_SIZE = 4 * COUNT_SIZE; // 4 counts
-static const int SPACE_SIZE = 3 * COUNT_SIZE; // 3 counts
-static const int FREQUENCY = 1020; // AIM 1-1-7 (f) specified in Hz
-
-static char alphabet[26][4] = {
- { DI, DAH, end, end }, /* A */
- { DA, DI, DI, DIT }, /* B */
- { DA, DI, DA, DIT }, /* C */
- { DA, DI, DIT, end }, /* D */
- { DIT, end, end, end }, /* E */
- { DI, DI, DA, DIT }, /* F */
- { DA, DA, DIT, end }, /* G */
- { DI, DI, DI, DIT }, /* H */
- { DI, DIT, end, end }, /* I */
- { DI, DA, DA, DAH }, /* J */
- { DA, DI, DAH, end }, /* K */
- { DI, DA, DI, DIT }, /* L */
- { DA, DAH, end, end }, /* M */
- { DA, DIT, end, end }, /* N */
- { DA, DA, DAH, end }, /* O */
- { DI, DA, DA, DIT }, /* P */
- { DA, DA, DI, DAH }, /* Q */
- { DI, DA, DIT, end }, /* R */
- { DI, DI, DIT, end }, /* S */
- { DAH, end, end, end }, /* T */
- { DI, DI, DAH, end }, /* U */
- { DI, DI, DI, DAH }, /* V */
- { DI, DA, DAH, end }, /* W */
- { DA, DI, DI, DAH }, /* X */
- { DA, DI, DA, DAH }, /* Y */
- { DA, DA, DI, DIT } /* Z */
-};
-
-// manages everything we need to know for an individual sound sample
-class FGMorse {
-
- unsigned char dit[ DIT_SIZE ] ;
- unsigned char dah[ DAH_SIZE ] ;
- unsigned char space[ SPACE_SIZE ] ;
-
-public:
-
- FGMorse();
- ~FGMorse();
-
- // allocate and initialize sound samples
- bool init();
-
- // make a FGSimpleSound morse code transmission for the specified string
- FGSimpleSound *make_ident( const string& id );
-};
-
-
-#endif // _MORSE_HXX
-
-
+++ /dev/null
-// soundmgr.cxx -- Sound effect management class
-//
-// Sound manager initially written by David Findlay
-// <david_j_findlay@yahoo.com.au> 2001
-//
-// C++-ified by Curtis Olson, started March 2001.
-//
-// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-//
-// $Id$
-
-
-#include <simgear/debug/logstream.hxx>
-#include <simgear/misc/fgpath.hxx>
-
-#include "globals.hxx"
-#include "soundmgr.hxx"
-
-
-// constructor
-FGSimpleSound::FGSimpleSound( string file ) {
- FGPath slfile( globals->get_fg_root() );
- slfile.append( file );
- sample = new slSample ( (char *)slfile.c_str() );
- pitch_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
- volume_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
- pitch_envelope->setStep ( 0, 0.01, 1.0 );
- volume_envelope->setStep ( 0, 0.01, 1.0 );
-}
-
-FGSimpleSound::FGSimpleSound( unsigned char *buffer, int len ) {
- sample = new slSample ( buffer, len );
- pitch_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
- volume_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
- pitch_envelope->setStep ( 0, 0.01, 1.0 );
- volume_envelope->setStep ( 0, 0.01, 1.0 );
-}
-
-// destructor
-FGSimpleSound::~FGSimpleSound() {
- delete pitch_envelope;
- delete volume_envelope;
- delete sample;
-}
-
-
-// constructor
-FGSoundMgr::FGSoundMgr() {
- audio_sched = new slScheduler( 8000 );
- audio_mixer = new smMixer;
-
- FG_LOG( FG_GENERAL, FG_INFO,
- "Rate = " << audio_sched->getRate()
- << " Bps = " << audio_sched->getBps()
- << " Stereo = " << audio_sched->getStereo() );
-}
-
-// destructor
-FGSoundMgr::~FGSoundMgr() {
- sound_map_iterator current = sounds.begin();
- sound_map_iterator end = sounds.end();
- for ( ; current != end; ++current ) {
- FGSimpleSound *s = current->second;
- delete s->get_sample();
- delete s;
- }
-
- delete audio_sched;
- delete audio_mixer;
-}
-
-
-// initialize the sound manager
-bool FGSoundMgr::init() {
- audio_mixer -> setMasterVolume ( 80 ) ; /* 80% of max volume. */
- audio_sched -> setSafetyMargin ( 1.0 ) ;
-
- sound_map_iterator current = sounds.begin();
- sound_map_iterator end = sounds.end();
- for ( ; current != end; ++current ) {
- FGSimpleSound *s = current->second;
- delete s->get_sample();
- delete s;
- }
- sounds.clear();
-
- if ( audio_sched->not_working() ) {
- return false;
- } else {
- return true;
- }
-}
-
-
-// run the audio scheduler
-bool FGSoundMgr::update() {
- if ( !audio_sched->not_working() ) {
- audio_sched -> update();
- return true;
- } else {
- return false;
- }
-}
-
-
-// add a sound effect
-bool FGSoundMgr::add( FGSimpleSound *sound, const string& refname ) {
- sounds[refname] = sound;
-
- return true;
-}
-
-
-// tell the scheduler to play the indexed sample in a continuous
-// loop
-bool FGSoundMgr::play_looped( const string& refname ) {
- sound_map_iterator it = sounds.find( refname );
- if ( it != sounds.end() ) {
- FGSimpleSound *sample = it->second;
- audio_sched->loopSample( sample->get_sample() );
- audio_sched->addSampleEnvelope( sample->get_sample(), 0, 0,
- sample->get_pitch_envelope(),
- SL_PITCH_ENVELOPE );
- audio_sched->addSampleEnvelope( sample->get_sample(), 0, 1,
- sample->get_volume_envelope(),
- SL_VOLUME_ENVELOPE );
-
- return true;
- } else {
- return false;
- }
-}
-
-
-// tell the scheduler to play the indexed sample once
-bool FGSoundMgr::FGSoundMgr::play_once( const string& refname ) {
- sound_map_iterator it = sounds.find( refname );
- if ( it != sounds.end() ) {
- FGSimpleSound *sample = it->second;
- audio_sched->playSample( sample->get_sample() );
- audio_sched->addSampleEnvelope( sample->get_sample(), 0, 0,
- sample->get_pitch_envelope(),
- SL_PITCH_ENVELOPE );
- audio_sched->addSampleEnvelope( sample->get_sample(), 0, 1,
- sample->get_volume_envelope(),
- SL_VOLUME_ENVELOPE );
-
- return true;
- } else {
- return false;
- }
-}
+++ /dev/null
-// soundmgr.hxx -- Sound effect management class
-//
-// Sound manager initially written by David Findlay
-// <david_j_findlay@yahoo.com.au> 2001
-//
-// C++-ified by Curtis Olson, started March 2001.
-//
-// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-//
-// $Id$
-
-
-#ifndef _SOUNDMGR_HXX
-#define _SOUNDMGR_HXX
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <simgear/compiler.h>
-
-#include STL_STRING
-#include <map>
-
-#include <plib/sl.h>
-#include <plib/sm.h>
-
-FG_USING_STD(map);
-FG_USING_STD(string);
-
-
-// manages everything we need to know for an individual sound sample
-class FGSimpleSound {
-
- slSample *sample;
- slEnvelope *pitch_envelope;
- slEnvelope *volume_envelope;
- double pitch;
- double volume;
-
-public:
-
- FGSimpleSound( string file );
- FGSimpleSound( unsigned char *buffer, int len );
- ~FGSimpleSound();
-
- inline double get_pitch() const { return pitch; }
- inline void set_pitch( double p ) {
- pitch = p;
- pitch_envelope->setStep( 0, 0.01, pitch );
- }
- inline double get_volume() const { return volume; }
- inline void set_volume( double v ) {
- volume = v;
- volume_envelope->setStep( 0, 0.01, volume );
- }
-
- inline slSample *get_sample() { return sample; }
- inline slEnvelope *get_pitch_envelope() { return pitch_envelope; }
- inline slEnvelope *get_volume_envelope() { return volume_envelope; }
-};
-
-
-typedef map < string, FGSimpleSound * > sound_map;
-typedef sound_map::iterator sound_map_iterator;
-typedef sound_map::const_iterator const_sound_map_iterator;
-
-
-class FGSoundMgr {
-
- slScheduler *audio_sched;
- smMixer *audio_mixer;
- sound_map sounds;
-
-public:
-
- FGSoundMgr();
- ~FGSoundMgr();
-
- // initialize the sound manager
- bool init();
-
- // run the audio scheduler
- bool update();
-
- // is audio working?
- inline bool is_working() const { return !audio_sched->not_working(); }
-
- // add a sound effect, return the index of the sound
- bool add( FGSimpleSound *sound, const string& refname );
-
- // tell the scheduler to play the indexed sample in a continuous
- // loop
- bool play_looped( const string& refname );
-
- // tell the scheduler to play the indexed sample once
- bool play_once( const string& refname );
-};
-
-
-#endif // _SOUNDMGR_HXX
-
-
$(NETWORK_DIRS) \
Objects \
Scenery \
+ Sound \
Time \
$(WEATHER_DIR) \
Main
--- /dev/null
+noinst_LIBRARIES = libSound.a
+
+libSound_a_SOURCES = \
+ morse.cxx morse.hxx \
+ soundmgr.cxx soundmgr.hxx
+
+INCLUDES += -I$(top_srcdir) -I$(top_srcdir)/src
--- /dev/null
+// morse.cxx -- Morse code generation class
+//
+// Written by Curtis Olson, started March 2001.
+//
+// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+
+#include "morse.hxx"
+
+
+static const char alphabet[26][4] = {
+ { DI, DAH, end, end }, /* A */
+ { DA, DI, DI, DIT }, /* B */
+ { DA, DI, DA, DIT }, /* C */
+ { DA, DI, DIT, end }, /* D */
+ { DIT, end, end, end }, /* E */
+ { DI, DI, DA, DIT }, /* F */
+ { DA, DA, DIT, end }, /* G */
+ { DI, DI, DI, DIT }, /* H */
+ { DI, DIT, end, end }, /* I */
+ { DI, DA, DA, DAH }, /* J */
+ { DA, DI, DAH, end }, /* K */
+ { DI, DA, DI, DIT }, /* L */
+ { DA, DAH, end, end }, /* M */
+ { DA, DIT, end, end }, /* N */
+ { DA, DA, DAH, end }, /* O */
+ { DI, DA, DA, DIT }, /* P */
+ { DA, DA, DI, DAH }, /* Q */
+ { DI, DA, DIT, end }, /* R */
+ { DI, DI, DIT, end }, /* S */
+ { DAH, end, end, end }, /* T */
+ { DI, DI, DAH, end }, /* U */
+ { DI, DI, DI, DAH }, /* V */
+ { DI, DA, DAH, end }, /* W */
+ { DA, DI, DI, DAH }, /* X */
+ { DA, DI, DA, DAH }, /* Y */
+ { DA, DA, DI, DIT } /* Z */
+};
+
+
+// constructor
+FGMorse::FGMorse() {
+}
+
+// destructor
+FGMorse::~FGMorse() {
+}
+
+
+// allocate and initialize sound samples
+bool FGMorse::init() {
+ int i, j;
+
+ // Make DIT
+ for ( i = 0; i < TRANSITION_BYTES; ++i ) {
+ float level = ( sin( (double) i * 2.0 * M_PI / (8000.0 / FREQUENCY)) )
+ * ((double)i / TRANSITION_BYTES) / 2.0 + 0.5;
+
+ /* Convert to unsigned byte */
+ dit[ i ] = (unsigned char) ( level * 255.0 ) ;
+ }
+
+ for ( i = TRANSITION_BYTES;
+ i < DIT_SIZE - TRANSITION_BYTES - COUNT_SIZE; ++i ) {
+ float level = ( sin( (double) i * 2.0 * M_PI / (8000.0 / FREQUENCY) ) )
+ / 2.0 + 0.5;
+
+ /* Convert to unsigned byte */
+ dit[ i ] = (unsigned char) ( level * 255.0 ) ;
+ }
+ j = TRANSITION_BYTES;
+ for ( i = DIT_SIZE - TRANSITION_BYTES - COUNT_SIZE;
+ i < DIT_SIZE - COUNT_SIZE;
+ ++i ) {
+ float level = ( sin( (double) i * 2.0 * M_PI / (8000.0 / FREQUENCY) ) )
+ * ((double)j / TRANSITION_BYTES) / 2.0 + 0.5;
+ --j;
+
+ /* Convert to unsigned byte */
+ dit[ i ] = (unsigned char) ( level * 255.0 ) ;
+ }
+ for ( i = DIT_SIZE - COUNT_SIZE; i < DIT_SIZE; ++i ) {
+ dit[ i ] = (unsigned char) ( 0.5 * 255.0 ) ;
+ }
+
+ // Make DAH
+ for ( i = 0; i < TRANSITION_BYTES; ++i ) {
+ float level = ( sin( (double) i * 2.0 * M_PI / (8000.0 / FREQUENCY) ) )
+ * ((double)i / TRANSITION_BYTES) / 2.0 + 0.5;
+
+ /* Convert to unsigned byte */
+ dah[ i ] = (unsigned char) ( level * 255.0 ) ;
+ }
+
+ for ( i = TRANSITION_BYTES;
+ i < DAH_SIZE - TRANSITION_BYTES - COUNT_SIZE;
+ ++i ) {
+ float level = ( sin( (double) i * 2.0 * M_PI / (8000.0 / FREQUENCY) ) )
+ / 2.0 + 0.5;
+
+ /* Convert to unsigned byte */
+ dah[ i ] = (unsigned char) ( level * 255.0 ) ;
+ }
+ j = TRANSITION_BYTES;
+ for ( int i = DAH_SIZE - TRANSITION_BYTES - COUNT_SIZE;
+ i < DAH_SIZE - COUNT_SIZE;
+ ++i ) {
+ float level = ( sin( (double) i * 2.0 * M_PI / (8000.0 / FREQUENCY) ) )
+ * ((double)j / TRANSITION_BYTES) / 2.0 + 0.5;
+ --j;
+
+ /* Convert to unsigned byte */
+ dah[ i ] = (unsigned char) ( level * 255.0 ) ;
+ }
+ for ( int i = DAH_SIZE - COUNT_SIZE; i < DAH_SIZE; ++i ) {
+ dah[ i ] = (unsigned char) ( 0.5 * 255.0 ) ;
+ }
+
+ // Make SPACE
+ for ( int i = 0; i < SPACE_SIZE; ++i ) {
+ space[ i ] = (unsigned char) ( 0.5 * 255 ) ;
+ }
+
+ return true;
+}
+
+
+// make a FGSimpleSound morse code transmission for the specified string
+FGSimpleSound *FGMorse::make_ident( const string& id ) {
+ char *idptr = (char *)id.c_str();
+
+ int length = 0;
+ int i, j;
+
+ // 1. Determine byte length of message
+ for ( i = 0; i < (int)id.length(); ++i ) {
+ if ( idptr[i] >= 'A' && idptr[i] <= 'Z' ) {
+ char c = idptr[i] - 'A';
+ for ( j = 0; j < 4 || alphabet[c][j] == end; ++j ) {
+ if ( alphabet[c][j] == DIT ) {
+ length += DIT_SIZE;
+ } else if ( alphabet[c][j] == DAH ) {
+ length += DAH_SIZE;
+ }
+ }
+ length += SPACE_SIZE;
+ } else {
+ // skip unknown character
+ }
+ }
+
+ // 2. Allocate space for the message
+ unsigned char *buffer = new unsigned char[length];
+
+ // 3. Assemble the message;
+ unsigned char *bufptr = buffer;
+
+ for ( i = 0; i < (int)id.length(); ++i ) {
+ if ( idptr[i] >= 'A' && idptr[i] <= 'Z' ) {
+ char c = idptr[i] - 'A';
+ for ( j = 0; j < 4 || alphabet[c][j] == end; ++j ) {
+ if ( alphabet[c][j] == DIT ) {
+ memcpy( bufptr, dit, DIT_SIZE );
+ bufptr += DIT_SIZE;
+ } else if ( alphabet[c][j] == DAH ) {
+ memcpy( bufptr, dah, DAH_SIZE );
+ bufptr += DAH_SIZE;
+ }
+ }
+ memcpy( bufptr, space, SPACE_SIZE );
+ bufptr += SPACE_SIZE;
+ } else {
+ // skip unknown character
+ }
+ }
+
+ // 4. create the simple sound and return
+ FGSimpleSound *sample = new FGSimpleSound( buffer, length );
+
+ return sample;
+}
--- /dev/null
+// morse.hxx -- Morse code generation class
+//
+// Written by Curtis Olson, started March 2001.
+//
+// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+
+#ifndef _MORSE_HXX
+#define _MORSE_HXX
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <simgear/compiler.h>
+
+#include <plib/sl.h>
+#include <plib/sm.h>
+
+#include "soundmgr.hxx"
+
+
+// Quoting from http://www.kluft.com/~ikluft/ham/morse-intro.html by
+// Ian Kluft KO6YQ <ikluft@kluft.com>
+//
+// [begin quote]
+//
+// What is the Standard for Measuring Morse Code Speed?
+//
+// [This was adapted from the Ham Radio FAQ which used to be posted on UseNet.]
+//
+// The word PARIS was chosen as the standard length for CW code
+// speed. Each dit counts for one count, each dah counts for three
+// counts, intra-character spacing is one count, inter-character
+// spacing is three counts and inter-word spacing is seven counts, so
+// the word PARIS is exactly 50 counts:
+//
+// PPPPPPPPPPPPPP AAAAAA RRRRRRRRRR IIIIII SSSSSSSSSS
+// di da da di di da di da di di di di di di
+// 1 1 3 1 3 1 1 3 1 1 3 3 1 1 3 1 1 3 1 1 1 3 1 1 1 1 1 7 = 50
+// ^ ^ ^
+// ^Intra-character ^Inter-character Inter-word^
+//
+// So 5 words-per-minute = 250 counts-per-minute / 50 counts-per-word
+// or one count every 240 milliseconds. 13 words-per-minute is one
+// count every ~92.3 milliseconds. This method of sending code is
+// sometimes called "Slow Code", because at 5 wpm it sounds VERY SLOW.
+//
+// The "Farnsworth" method is accomplished by sending the dits and
+// dahs and intra-character spacing at a higher speed, then increasing
+// the inter-character and inter-word spacing to slow the sending
+// speed down to the desired speed. For example, to send at 5 wpm with
+// 13 wpm characters in Farnsworth method, the dits and
+// intra-character spacing would be 92.3 milliseconds, the dah would
+// be 276.9 milliseconds, the inter-character spacing would be 1.443
+// seconds and inter-word spacing would be 3.367 seconds.
+//
+// [end quote]
+
+// Ok, back to Curt
+
+// My formulation is based dit = 1 count, dah = 3 counts, 1 count for
+// intRA-character space, 3 counts for intER-character space. Target
+// is 5 wpm which by the above means 1 count = 240 milliseconds.
+//
+// AIM 1-1-7 (f) states that the frequency of the tone should be 1020
+// Hz for the VOR ident.
+
+
+static const char DI = '1';
+static const char DIT = '1';
+static const char DA = '2';
+static const char DAH = '2';
+static const char end = '0';
+
+static const int BYTES_PER_SECOND = 8000;
+static const int BEAT_LENGTH = 240; // milleseconds (5 wpm)
+// static const int BEAT_LENGTH = 92; // milleseconds (13 wpm)
+static const int TRANSITION_BYTES = (int)(0.005 * BYTES_PER_SECOND);
+static const int COUNT_SIZE = BYTES_PER_SECOND * BEAT_LENGTH / 1000;
+static const int DIT_SIZE = 2 * COUNT_SIZE; // 2 counts
+static const int DAH_SIZE = 4 * COUNT_SIZE; // 4 counts
+static const int SPACE_SIZE = 3 * COUNT_SIZE; // 3 counts
+static const int FREQUENCY = 1020; // AIM 1-1-7 (f) specified in Hz
+
+// manages everything we need to know for an individual sound sample
+class FGMorse {
+
+ unsigned char dit[ DIT_SIZE ] ;
+ unsigned char dah[ DAH_SIZE ] ;
+ unsigned char space[ SPACE_SIZE ] ;
+
+public:
+
+ FGMorse();
+ ~FGMorse();
+
+ // allocate and initialize sound samples
+ bool init();
+
+ // make a FGSimpleSound morse code transmission for the specified string
+ FGSimpleSound *make_ident( const string& id );
+};
+
+
+#endif // _MORSE_HXX
+
+
--- /dev/null
+// soundmgr.cxx -- Sound effect management class
+//
+// Sound manager initially written by David Findlay
+// <david_j_findlay@yahoo.com.au> 2001
+//
+// C++-ified by Curtis Olson, started March 2001.
+//
+// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/misc/fgpath.hxx>
+
+#include <Main/globals.hxx>
+
+#include "soundmgr.hxx"
+
+
+// constructor
+FGSimpleSound::FGSimpleSound( string file ) {
+ FGPath slfile( globals->get_fg_root() );
+ slfile.append( file );
+ sample = new slSample ( (char *)slfile.c_str() );
+ pitch_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
+ volume_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
+ pitch_envelope->setStep ( 0, 0.01, 1.0 );
+ volume_envelope->setStep ( 0, 0.01, 1.0 );
+}
+
+FGSimpleSound::FGSimpleSound( unsigned char *buffer, int len ) {
+ sample = new slSample ( buffer, len );
+ pitch_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
+ volume_envelope = new slEnvelope( 1, SL_SAMPLE_ONE_SHOT );
+ pitch_envelope->setStep ( 0, 0.01, 1.0 );
+ volume_envelope->setStep ( 0, 0.01, 1.0 );
+}
+
+// destructor
+FGSimpleSound::~FGSimpleSound() {
+ delete pitch_envelope;
+ delete volume_envelope;
+ delete sample;
+}
+
+
+// constructor
+FGSoundMgr::FGSoundMgr() {
+ audio_sched = new slScheduler( 8000 );
+ audio_mixer = new smMixer;
+
+ FG_LOG( FG_GENERAL, FG_INFO,
+ "Rate = " << audio_sched->getRate()
+ << " Bps = " << audio_sched->getBps()
+ << " Stereo = " << audio_sched->getStereo() );
+}
+
+// destructor
+FGSoundMgr::~FGSoundMgr() {
+ sound_map_iterator current = sounds.begin();
+ sound_map_iterator end = sounds.end();
+ for ( ; current != end; ++current ) {
+ FGSimpleSound *s = current->second;
+ delete s->get_sample();
+ delete s;
+ }
+
+ delete audio_sched;
+ delete audio_mixer;
+}
+
+
+// initialize the sound manager
+bool FGSoundMgr::init() {
+ audio_mixer -> setMasterVolume ( 80 ) ; /* 80% of max volume. */
+ audio_sched -> setSafetyMargin ( 1.0 ) ;
+
+ sound_map_iterator current = sounds.begin();
+ sound_map_iterator end = sounds.end();
+ for ( ; current != end; ++current ) {
+ FGSimpleSound *s = current->second;
+ delete s->get_sample();
+ delete s;
+ }
+ sounds.clear();
+
+ if ( audio_sched->not_working() ) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+
+// run the audio scheduler
+bool FGSoundMgr::update() {
+ if ( !audio_sched->not_working() ) {
+ audio_sched -> update();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+// add a sound effect
+bool FGSoundMgr::add( FGSimpleSound *sound, const string& refname ) {
+ sounds[refname] = sound;
+
+ return true;
+}
+
+
+// tell the scheduler to play the indexed sample in a continuous
+// loop
+bool FGSoundMgr::play_looped( const string& refname ) {
+ sound_map_iterator it = sounds.find( refname );
+ if ( it != sounds.end() ) {
+ FGSimpleSound *sample = it->second;
+ audio_sched->loopSample( sample->get_sample() );
+ audio_sched->addSampleEnvelope( sample->get_sample(), 0, 0,
+ sample->get_pitch_envelope(),
+ SL_PITCH_ENVELOPE );
+ audio_sched->addSampleEnvelope( sample->get_sample(), 0, 1,
+ sample->get_volume_envelope(),
+ SL_VOLUME_ENVELOPE );
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+// tell the scheduler to play the indexed sample once
+bool FGSoundMgr::FGSoundMgr::play_once( const string& refname ) {
+ sound_map_iterator it = sounds.find( refname );
+ if ( it != sounds.end() ) {
+ FGSimpleSound *sample = it->second;
+ audio_sched->playSample( sample->get_sample() );
+ audio_sched->addSampleEnvelope( sample->get_sample(), 0, 0,
+ sample->get_pitch_envelope(),
+ SL_PITCH_ENVELOPE );
+ audio_sched->addSampleEnvelope( sample->get_sample(), 0, 1,
+ sample->get_volume_envelope(),
+ SL_VOLUME_ENVELOPE );
+
+ return true;
+ } else {
+ return false;
+ }
+}