Example #1
0
void SystemView::PutBody(const SystemBody *b, const vector3d &offset, const matrix4x4f &trans)
{
	if (b->type == SystemBody::TYPE_STARPORT_SURFACE) return;
	if (b->type != SystemBody::TYPE_GRAVPOINT) {

		if (!m_bodyIcon) {
			m_bodyIcon.reset(new Graphics::Drawables::Disk(m_renderer, Color::WHITE, 1.0f));
		}

		const double radius = b->GetRadius() * m_zoom;

		matrix4x4f invRot = trans;
		invRot.ClearToRotOnly();
		invRot = invRot.InverseOf();

		matrix4x4f bodyTrans = trans;
		bodyTrans.Translate(vector3f(offset));
		bodyTrans.Scale(radius);
		m_renderer->SetTransform(bodyTrans * invRot);
		m_bodyIcon->Draw(m_renderer);

		m_renderer->SetTransform(trans);

		PutLabel(b, offset);
	}

	Frame *frame = Pi::player->GetFrame();
	if(frame->IsRotFrame()) frame = frame->GetNonRotFrame();
	if(frame->GetSystemBody() == b && frame->GetSystemBody()->GetMass() > 0) {
		const double t0 = Pi::game->GetTime();
		Orbit playerOrbit = Pi::player->ComputeOrbit();
		PutOrbit(&playerOrbit, offset, Color::RED, b->GetRadius());
		PutSelectionBox(offset + playerOrbit.OrbitalPosAtTime(m_time - t0)* double(m_zoom), Color::RED);
	}

	if (b->children.size()) {
		for(std::vector<SystemBody*>::const_iterator kid = b->children.begin(); kid != b->children.end(); ++kid) {
			if (is_zero_general((*kid)->orbit.GetSemiMajorAxis())) continue;
			if ((*kid)->orbit.GetSemiMajorAxis() * m_zoom < ROUGH_SIZE_OF_TURD) {
				PutOrbit(&((*kid)->orbit), offset, Color(0, 255, 0, 255));
			}

			// not using current time yet
			vector3d pos = (*kid)->orbit.OrbitalPosAtTime(m_time);
			pos *= double(m_zoom);

			PutBody(*kid, offset + pos, trans);
		}
	}
}
Example #2
0
void TransferPlanner::AddStartTime(double timeStep) {
	if(std::fabs(m_startTime) < 1.)
		m_startTime = Pi::game->GetTime(); 

	m_startTime += m_factor * timeStep;
	double deltaT = m_startTime - Pi::game->GetTime();
	if(deltaT > 0.)
	{
		Frame *frame = Pi::player->GetFrame()->GetNonRotFrame();
		Orbit playerOrbit = Orbit::FromBodyState(Pi::player->GetPositionRelTo(frame), Pi::player->GetVelocityRelTo(frame), frame->GetSystemBody()->GetMass());

		m_position = playerOrbit.OrbitalPosAtTime(deltaT);
		m_velocity = playerOrbit.OrbitalVelocityAtTime(frame->GetSystemBody()->GetMass(), deltaT);
	}
	else
		ResetStartTime();
}
Example #3
0
void AmbientSounds::Update()
{
	const float v_env = (Pi::worldView->GetCameraController()->IsExternal() ? 1.0f : 0.5f) * Sound::GetSfxVolume();

	if (Pi::player->GetFlightState() == Ship::DOCKED) {
		if (s_starNoise.IsPlaying()) {
			const float target[2] = {0.0f,0.0f};
			const float dv_dt[2] = {1.0f,1.0f};
			s_starNoise.VolumeAnimate(target, dv_dt);
			s_starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}
		for(int i=0; i<eMaxNumAtmosphereSounds; i++) {
			if (s_atmosphereNoises[i].IsPlaying()) {
				const float target[2] = {0.0f,0.0f};
				const float dv_dt[2] = {1.0f,1.0f};
				s_atmosphereNoises[i].VolumeAnimate(target, dv_dt);
				s_atmosphereNoises[i].SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
			}
		}
		if (s_planetSurfaceNoise.IsPlaying()) {
			const float target[2] = {0.0f,0.0f};
			const float dv_dt[2] = {1.0f,1.0f};
			s_planetSurfaceNoise.VolumeAnimate(target, dv_dt);
			s_planetSurfaceNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}

		if (!s_stationNoise.IsPlaying()) {
			// just use a random station noise until we have a
			// concept of 'station size'
			s_stationNoise.Play(s_stationNoiseSounds[Pi::player->GetDockedWith()->GetSystemBody()->GetSeed() % NUM_STATION_SOUNDS],
					0.3f*v_env, 0.3f*v_env, Sound::OP_REPEAT);
		}
	} else if (Pi::player->GetFlightState() == Ship::LANDED) {
		/* Planet surface noise on rough-landing */
		if (s_starNoise.IsPlaying()) {
			const float target[2] = {0.0f,0.0f};
			const float dv_dt[2] = {1.0f,1.0f};
			s_starNoise.VolumeAnimate(target, dv_dt);
			s_starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}
		for(int i=0; i<eMaxNumAtmosphereSounds; i++) {
			if (s_atmosphereNoises[i].IsPlaying()) {
				const float target[2] = {0.0f,0.0f};
				const float dv_dt[2] = {1.0f,1.0f};
				s_atmosphereNoises[i].VolumeAnimate(target, dv_dt);
				s_atmosphereNoises[i].SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
			}
		}
		if (s_stationNoise.IsPlaying()) {
			const float target[2] = {0.0f,0.0f};
			const float dv_dt[2] = {1.0f,1.0f};
			s_stationNoise.VolumeAnimate(target, dv_dt);
			s_stationNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}

		// lets try something random for the time being
		if (!s_planetSurfaceNoise.IsPlaying()) {
			const SystemBody *sbody = Pi::player->GetFrame()->GetSystemBody();
			assert(sbody);
			const char *sample = 0;

			if (sbody->GetLifeAsFixed() > fixed(1,5)) {
				sample = s_surfaceLifeSounds[sbody->GetSeed() % NUM_SURFACE_LIFE_SOUNDS];
			}
			else if (sbody->GetVolatileGasAsFixed() > fixed(1,2)) {
				sample = s_surfaceSounds[sbody->GetSeed() % NUM_SURFACE_DEAD_SOUNDS];
			}
			else if (sbody->GetVolatileGasAsFixed() > fixed(1,10)) {
				sample = "Wind";
			}

			if (sample) {
				s_planetSurfaceNoise.Play(sample, 0.3f*v_env, 0.3f*v_env, Sound::OP_REPEAT);
			}
		}
    } else if (s_planetSurfaceNoise.IsPlaying()) {
        // s_planetSurfaceNoise.IsPlaying() - if we are out of the atmosphere then stop playing
        if (Pi::player->GetFrame()->IsRotFrame()) {
            const Body *astro = Pi::player->GetFrame()->GetBody();
            if (astro->IsType(Object::PLANET)) {
                const double dist = Pi::player->GetPosition().Length();
                double pressure, density;
                static_cast<const Planet*>(astro)->GetAtmosphericState(dist, &pressure, &density);
                if (pressure < 0.001) {
                    // Stop playing surface noise once out of the atmosphere
                    s_planetSurfaceNoise.Stop();
                }
            }
        }
    } else {
		if (s_stationNoise.IsPlaying()) {
			const float target[2] = {0.0f,0.0f};
			const float dv_dt[2] = {1.0f,1.0f};
			s_stationNoise.VolumeAnimate(target, dv_dt);
			s_stationNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}
		if (Pi::game->IsNormalSpace()) {
			StarSystem *s = Pi::game->GetSpace()->GetStarSystem().Get();
			if (astroNoiseSeed != s->GetSeed()) {
				// change sound!
				astroNoiseSeed = s->GetSeed();
				const float target[2] = {0.0f,0.0f};
				const float dv_dt[2] = {0.1f,0.1f};
				s_starNoise.VolumeAnimate(target, dv_dt);
				s_starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
				// XXX the way Sound::Event works isn't totally obvious.
				// to destroy the object doesn't stop the sound. it is
				// really just a sound event reference
				s_starNoise = Sound::Event();
			}
		}
		// when all the sounds are in we can use the body we are in frame of reference to
		if (!s_starNoise.IsPlaying()) {
			Frame *f = Pi::player->GetFrame();
			if (!f) return; // When player has no frame (game abort) then get outta here!!
			const SystemBody *sbody = f->GetSystemBody();
			const char *sample = 0;
			for (; sbody && !sample; sbody = f->GetSystemBody()) {
				switch (sbody->GetType()) {
					case SystemBody::TYPE_BROWN_DWARF: sample = "Brown_Dwarf_Substellar_Object"; break;
					case SystemBody::TYPE_STAR_M: sample = "M_Red_Star"; break;
					case SystemBody::TYPE_STAR_K: sample = "K_Star"; break;
					case SystemBody::TYPE_WHITE_DWARF: sample = "White_Dwarf_Star"; break;
					case SystemBody::TYPE_STAR_G: sample = "G_Star"; break;
					case SystemBody::TYPE_STAR_F: sample = "F_Star"; break;
					case SystemBody::TYPE_STAR_A: sample = "A_Star"; break;
					case SystemBody::TYPE_STAR_B: sample = "B_Hot_Blue_STAR"; break;
					case SystemBody::TYPE_STAR_O: sample = "Blue_Super_Giant"; break;
					case SystemBody::TYPE_PLANET_GAS_GIANT: {
							if (sbody->GetMassAsFixed() > fixed(400,1)) {
								sample = "Very_Large_Gas_Giant";
							} else if (sbody->GetMassAsFixed() > fixed(80,1)) {
								sample = "Large_Gas_Giant";
							} else if (sbody->GetMassAsFixed() > fixed(20,1)) {
								sample = "Medium_Gas_Giant";
							} else {
								sample = "Small_Gas_Giant";
							}
						}
						break;
					default: sample = 0; break;
				}
				if (sample) {
					s_starNoise.Play(sample, 0.0f, 0.0f, Sound::OP_REPEAT);
					s_starNoise.VolumeAnimate(.3f*v_env, .3f*v_env, .05f, .05f);
				} else {
					// go up orbital hierarchy tree to see if we can find a sound
					f = f->GetParent();
					if (f == 0) break;
				}
			}
		}

		const Body *astro = Pi::player->GetFrame()->GetBody();
		if (astro && Pi::player->GetFrame()->IsRotFrame() && (astro->IsType(Object::PLANET))) {
			double dist = Pi::player->GetPosition().Length();
			double pressure, density;
			static_cast<const Planet*>(astro)->GetAtmosphericState(dist, &pressure, &density);
			// maximum volume at around 2km/sec at earth density, pressure
			const float pressureVolume = float(density * Pi::player->GetVelocity().Length() * 0.0005);
			//volume = Clamp(volume, 0.0f, 1.0f) * v_env;
			float volumes[eMaxNumAtmosphereSounds];
			for(int i=0; i<eMaxNumAtmosphereSounds; i++) {
				const float beg = s_rangeTable[i][0];
				const float inv = s_rangeTable[i][1];
				volumes[i] = Clamp((pressureVolume - beg) * inv, 0.0f, 1.0f) * v_env;
			}
			
			for(int i=0; i<eMaxNumAtmosphereSounds; i++) {
				const float volume = volumes[i];
				if (s_atmosphereNoises[i].IsPlaying()) {
					const float target[2] = {volume, volume};
					const float dv_dt[2] = {1.0f,1.0f};
					s_atmosphereNoises[i].VolumeAnimate(target, dv_dt);
				} else {
					s_atmosphereNoises[i].Play(s_airflowTable[i], volume, volume, Sound::OP_REPEAT);
				}
			}
		} else {
			const float target[2] = {0.0f,0.0f};
			const float dv_dt[2] = {1.0f,1.0f};
			for(int i=0; i<eMaxNumAtmosphereSounds; i++) {
				s_atmosphereNoises[i].VolumeAnimate(target, dv_dt);
				s_atmosphereNoises[i].SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
			}
		}
	}
}
Example #4
0
/*
 * Function: SpawnShipLandedNear
 *
 * Create a ship and place it on the surface near the given <Body>.
 *
 * > ship = Space.SpawnShipLandedNear(type, body, min, max)
 *
 * Parameters:
 *
 *   type - the name of the ship
 *
 *   body - the <Body> near which the ship should be spawned. It must be on the ground or close to it,
 *          i.e. it must be in the rotating frame of the planetary body.
 *
 *   min - minimum distance from the surface point below the body to place the ship, in Km
 *
 *   max - maximum distance to place the ship
 *
 * Return:
 *
 *   ship - a <Ship> object for the new ship
 *
 * Example:
 *
 * > -- spawn a ship 10km from the player
 * > local ship = Ship.SpawnShipLandedNear("viper_police", Game.player, 10, 10)
 *
 * Availability:
 *
 *   July 2013
 *
 * Status:
 *
 *   experimental
 */
static int l_space_spawn_ship_landed_near(lua_State *l)
{
    if (!Pi::game)
        luaL_error(l, "Game is not started");

    LUA_DEBUG_START(l);

    const char *type = luaL_checkstring(l, 1);
    if (! ShipType::Get(type))
        luaL_error(l, "Unknown ship type '%s'", type);

    Body *nearbody = LuaObject<Body>::CheckFromLua(2);
    const float min_dist = luaL_checknumber(l, 3);
    const float max_dist = luaL_checknumber(l, 4);
    if (min_dist > max_dist)
        luaL_error(l, "min_dist must not be larger than max_dist");

    Ship *ship = new Ship(type);
    assert(ship);

    // XXX protect against spawning inside the body
    Frame * newframe = nearbody->GetFrame()->GetRotFrame();
    if (!newframe->IsRotFrame())
        luaL_error(l, "Body must be in rotating frame");
    SystemBody *sbody = newframe->GetSystemBody();
    if (sbody->GetSuperType() != SystemBody::SUPERTYPE_ROCKY_PLANET)
        luaL_error(l, "Body is not on a rocky planet");
    if (max_dist > sbody->GetRadius())
        luaL_error(l, "max_dist too large for planet radius");
    // We assume that max_dist is much smaller than the planet radius, i.e. that our area is reasonably flat
    // So, we
    const vector3d up = nearbody->GetPosition().Normalized();
    vector3d x;
    vector3d y;
    // Calculate a orthonormal basis for a horizontal plane. For numerical reasons we do that determining the smallest
    // coordinate and take the cross product with (1,0,0), (0,1,0) or (0,0,1) respectively to calculate the first vector.
    // The second vector is just the cross product of the up-vector and out first vector.
    if (up.x <= up.y && up.x <= up.z) {
        x = vector3d(0.0, up.z, -up.y).Normalized();
        y = vector3d(-up.y*up.y - up.z*up.z, up.x*up.y, up.x*up.z).Normalized();
    } else if (up.y <= up.x && up.y <= up.z) {
        x = vector3d(-up.z, 0.0, up.x).Normalized();
        y = vector3d(up.x*up.y, -up.x*up.x - up.z*up.z, up.y*up.z).Normalized();
    } else {
        x = vector3d(up.y, -up.x, 0.0).Normalized();
        y = vector3d(up.x*up.z, up.y*up.z, -up.x*up.x - up.y*up.y).Normalized();
    }
    Planet *planet = static_cast<Planet*>(newframe->GetBody());
    const double radius = planet->GetSystemBody()->GetRadius();
    const vector3d planar = MathUtil::RandomPointInCircle(min_dist * 1000.0, max_dist * 1000.0);
    vector3d pos = (radius * up + x * planar.x + y * planar.y).Normalized();
    float latitude = atan2(pos.y, sqrt(pos.x*pos.x + pos.z * pos.z));
    float longitude = atan2(pos.x, pos.z);

    Pi::game->GetSpace()->AddBody(ship);
    ship->SetLandedOn(planet, latitude, longitude);

    LuaObject<Ship>::PushToLua(ship);

    LUA_DEBUG_END(l, 1);

    return 1;
}
Example #5
0
void SystemView::PutBody(const SystemBody *b, const vector3d &offset, const matrix4x4f &trans)
{
	if (b->GetType() == SystemBody::TYPE_STARPORT_SURFACE) 
		return;

	if (b->GetType() != SystemBody::TYPE_GRAVPOINT)
	{
		if (!m_bodyIcon) 
		{
			Graphics::RenderStateDesc rsd;
			auto solidState = m_renderer->CreateRenderState(rsd);
			m_bodyIcon.reset(new Graphics::Drawables::Disk(m_renderer, solidState, Color::WHITE, 1.0f));
		}

		const double radius = b->GetRadius() * m_zoom;

		matrix4x4f invRot = trans;
		invRot.ClearToRotOnly();
		invRot = invRot.Inverse();

		matrix4x4f bodyTrans = trans;
		bodyTrans.Translate(vector3f(offset));
		bodyTrans.Scale(radius);
		m_renderer->SetTransform(bodyTrans * invRot);
		m_bodyIcon->Draw(m_renderer);

		m_renderer->SetTransform(trans);

		PutLabel(b, offset);
	}

	Frame *frame = Pi::player->GetFrame();
	if(frame->IsRotFrame()) 
		frame = frame->GetNonRotFrame();

	// display the players orbit(?)
	if(frame->GetSystemBody() == b && frame->GetSystemBody()->GetMass() > 0) 
	{
		const double t0 = m_game->GetTime();
		Orbit playerOrbit = Pi::player->ComputeOrbit();

		PutOrbit(&playerOrbit, offset, Color::RED, b->GetRadius());

		const double plannerStartTime = m_planner->GetStartTime();
		if(!m_planner->GetPosition().ExactlyEqual(vector3d(0,0,0))) 
		{
			Orbit plannedOrbit = Orbit::FromBodyState(m_planner->GetPosition(),
								  m_planner->GetVel(),
								  frame->GetSystemBody()->GetMass());
			PutOrbit(&plannedOrbit, offset, Color::STEELBLUE, b->GetRadius());
			if(std::fabs(m_time - t0) > 1. && (m_time - plannerStartTime) > 0.)
				PutSelectionBox(offset + plannedOrbit.OrbitalPosAtTime(m_time - plannerStartTime) * static_cast<double>(m_zoom), Color::STEELBLUE);
			else
				PutSelectionBox(offset + m_planner->GetPosition() * static_cast<double>(m_zoom), Color::STEELBLUE);
				
		}

		PutSelectionBox(offset + playerOrbit.OrbitalPosAtTime(m_time - t0)* double(m_zoom), Color::RED);
	}

	// display all child bodies and their orbits
	if (b->HasChildren()) 
	{
		for(const SystemBody* kid : b->GetChildren()) 
		{
			if (is_zero_general(kid->GetOrbit().GetSemiMajorAxis())) 
				continue;

			const double axisZoom = kid->GetOrbit().GetSemiMajorAxis() * m_zoom;
			if (axisZoom < DEFAULT_VIEW_DISTANCE)
			{
				const SystemBody::BodySuperType bst = kid->GetSuperType();
				const bool showLagrange = (bst == SystemBody::SUPERTYPE_ROCKY_PLANET || bst == SystemBody::SUPERTYPE_GAS_GIANT);
				PutOrbit(&(kid->GetOrbit()), offset, Color::GREEN, 0.0, showLagrange);
			}

			// not using current time yet
			const vector3d pos = kid->GetOrbit().OrbitalPosAtTime(m_time) * double(m_zoom);
			PutBody(kid, offset + pos, trans);
		}
	}
}
Example #6
0
void AmbientSounds::Update()
{
	float v_env = (Pi::worldView->GetActiveCamera()->IsExternal() ? 1.0f : 0.5f) * Sound::GetSfxVolume();

	if (Pi::player->GetFlightState() == Ship::DOCKED) {
		if (starNoise.IsPlaying()) {
			float target[2] = {0.0f,0.0f};
			float dv_dt[2] = {1.0f,1.0f};
			starNoise.VolumeAnimate(target, dv_dt);
			starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}
		if (atmosphereNoise.IsPlaying()) {
			float target[2] = {0.0f,0.0f};
			float dv_dt[2] = {1.0f,1.0f};
			atmosphereNoise.VolumeAnimate(target, dv_dt);
			atmosphereNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}
		if (planetSurfaceNoise.IsPlaying()) {
			float target[2] = {0.0f,0.0f};
			float dv_dt[2] = {1.0f,1.0f};
			planetSurfaceNoise.VolumeAnimate(target, dv_dt);
			planetSurfaceNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}

		if (!stationNoise.IsPlaying()) {
			const char *sounds[] = {
				"Large_Station_ambient",
				"Medium_Station_ambient",
				"Small_Station_ambient"
			};
			// just use a random station noise until we have a
			// concept of 'station size'
			stationNoise.Play(sounds[Pi::player->GetDockedWith()->GetSystemBody()->seed % 3],
					0.3f*v_env, 0.3f*v_env, Sound::OP_REPEAT);
		}
	} else if (Pi::player->GetFlightState() == Ship::LANDED) {
		/* Planet surface noise on rough-landing */
		if (starNoise.IsPlaying()) {
			float target[2] = {0.0f,0.0f};
			float dv_dt[2] = {1.0f,1.0f};
			starNoise.VolumeAnimate(target, dv_dt);
			starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}
		if (atmosphereNoise.IsPlaying()) {
			float target[2] = {0.0f,0.0f};
			float dv_dt[2] = {1.0f,1.0f};
			atmosphereNoise.VolumeAnimate(target, dv_dt);
			atmosphereNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}
		if (stationNoise.IsPlaying()) {
			float target[2] = {0.0f,0.0f};
			float dv_dt[2] = {1.0f,1.0f};
			stationNoise.VolumeAnimate(target, dv_dt);
			stationNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}

		// lets try something random for the time being
		if (!planetSurfaceNoise.IsPlaying()) {
			SystemBody *sbody = Pi::player->GetFrame()->GetSystemBody();
			assert(sbody);
			const char *sample = NULL;

			if (sbody->m_life > fixed(1,5)) {
				const char *s[] = {
					"Wind", "Thunder_1", "Thunder_2", "Thunder_3",
					"Thunder_4", "Storm", "Rain_Light", "River",
					"RainForestIntroducedNight", "RainForestIntroduced",
					"NormalForestIntroduced"
				};
				sample = s[sbody->seed % 11];
			}
			else if (sbody->m_volatileGas > fixed(1,2)) {
				const char *s[] = {
					"Wind", "Thunder_1", "Thunder_2", "Thunder_3",
					"Thunder_4", "Storm"
				};
				sample = s[sbody->seed % 6];
			}
			else if (sbody->m_volatileGas > fixed(1,10)) {
				sample = "Wind";
			}

			if (sample) {
				planetSurfaceNoise.Play(sample, 0.3f*v_env, 0.3f*v_env, Sound::OP_REPEAT);
			}
		}
    } else if (planetSurfaceNoise.IsPlaying()) {
        // planetSurfaceNoise.IsPlaying() - if we are out of the atmosphere then stop playing
        if (Pi::player->GetFrame()->IsRotFrame()) {
            Body *astro = Pi::player->GetFrame()->GetBody();
            if (astro->IsType(Object::PLANET)) {
                double dist = Pi::player->GetPosition().Length();
                double pressure, density;
                static_cast<Planet*>(astro)->GetAtmosphericState(dist, &pressure, &density);
                if (pressure < 0.001) {
                    // Stop playing surface noise once out of the atmosphere
                    planetSurfaceNoise.Stop();
                }
            }
        }
    } else {
		if (stationNoise.IsPlaying()) {
			float target[2] = {0.0f,0.0f};
			float dv_dt[2] = {1.0f,1.0f};
			stationNoise.VolumeAnimate(target, dv_dt);
			stationNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}
		{
			if (Pi::game->IsNormalSpace()) {
				StarSystem *s = Pi::game->GetSpace()->GetStarSystem().Get();
				if (astroNoiseSeed != s->GetSeed()) {
					// change sound!
					astroNoiseSeed = s->GetSeed();
					float target[2] = {0.0f,0.0f};
					float dv_dt[2] = {0.1f,0.1f};
					starNoise.VolumeAnimate(target, dv_dt);
					starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
					// XXX the way Sound::Event works isn't totally obvious.
					// to destroy the object doesn't stop the sound. it is
					// really just a sound event reference
					starNoise = Sound::Event();
				}
			}
		}
		// when all the sounds are in we can use the body we are in frame of reference to
		if (!starNoise.IsPlaying()) {
			Frame *f = Pi::player->GetFrame();
			if (!f) return; // When player has no frame (game abort) then get outta here!!
			const SystemBody *sbody = f->GetSystemBody();
			const char *sample = 0;
			for (; sbody && !sample; sbody = f->GetSystemBody()) {
				switch (sbody->type) {
					case SystemBody::TYPE_BROWN_DWARF: sample = "Brown_Dwarf_Substellar_Object"; break;
					case SystemBody::TYPE_STAR_M: sample = "M_Red_Star"; break;
					case SystemBody::TYPE_STAR_K: sample = "K_Star"; break;
					case SystemBody::TYPE_WHITE_DWARF: sample = "White_Dwarf_Star"; break;
					case SystemBody::TYPE_STAR_G: sample = "G_Star"; break;
					case SystemBody::TYPE_STAR_F: sample = "F_Star"; break;
					case SystemBody::TYPE_STAR_A: sample = "A_Star"; break;
					case SystemBody::TYPE_STAR_B: sample = "B_Hot_Blue_STAR"; break;
					case SystemBody::TYPE_STAR_O: sample = "Blue_Super_Giant"; break;
					case SystemBody::TYPE_PLANET_GAS_GIANT: {
							if (sbody->mass > fixed(400,1)) {
								sample = "Very_Large_Gas_Giant";
							} else if (sbody->mass > fixed(80,1)) {
								sample = "Large_Gas_Giant";
							} else if (sbody->mass > fixed(20,1)) {
								sample = "Medium_Gas_Giant";
							} else {
								sample = "Small_Gas_Giant";
							}
						}
						break;
					default: sample = 0; break;
				}
				if (sample) {
					starNoise.Play(sample, 0.0f, 0.0f, Sound::OP_REPEAT);
					starNoise.VolumeAnimate(.3f*v_env, .3f*v_env, .05f, .05f);
				} else {
					// go up orbital hierarchy tree to see if we can find a sound
					f = f->GetParent();
					if (f == 0) break;
				}
			}
		}

		Body *astro;
		if ((astro = Pi::player->GetFrame()->GetBody())
			&& Pi::player->GetFrame()->IsRotFrame() && (astro->IsType(Object::PLANET))) {
			double dist = Pi::player->GetPosition().Length();
			double pressure, density;
			static_cast<Planet*>(astro)->GetAtmosphericState(dist, &pressure, &density);
			// maximum volume at around 2km/sec at earth density, pressure
			float volume = float(density * Pi::player->GetVelocity().Length() * 0.0005);
			volume = Clamp(volume, 0.0f, 1.0f) * v_env;
			if (atmosphereNoise.IsPlaying()) {
				float target[2] = {volume, volume};
				float dv_dt[2] = {1.0f,1.0f};
				atmosphereNoise.VolumeAnimate(target, dv_dt);
			} else {
				atmosphereNoise.Play("Atmosphere_Flying", volume, volume, Sound::OP_REPEAT);
			}
		} else {
			float target[2] = {0.0f,0.0f};
			float dv_dt[2] = {1.0f,1.0f};
			atmosphereNoise.VolumeAnimate(target, dv_dt);
			atmosphereNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}
	}
}