From 907a3e6441639b27f7932d72841965dc4e9d9a87 Mon Sep 17 00:00:00 2001 From: cim Date: Mon, 11 Nov 2013 22:45:05 +0000 Subject: [PATCH] Basic positional support for built-in sounds - needs soundset to be in mono - no support yet for scripting soundsource positions --- src/Core/Entities/PlayerEntity.h | 1 + src/Core/Entities/PlayerEntity.m | 41 ++++++++---- src/Core/Entities/PlayerEntityControls.m | 2 +- src/Core/Entities/PlayerEntitySound.h | 17 +++-- src/Core/Entities/PlayerEntitySound.m | 80 +++++++++++++++--------- src/Core/Entities/ShipEntity.h | 2 + src/Core/Entities/ShipEntity.m | 62 +++++++++++------- src/Core/OOALSoundChannel.h | 3 + src/Core/OOALSoundChannel.m | 10 +++ src/Core/OOOpenALController.m | 1 + src/Core/OOSoundSource.h | 5 +- src/Core/OOSoundSource.m | 26 +++++++- src/Core/OOSoundSourcePool.h | 16 ++++- src/Core/OOSoundSourcePool.m | 37 ++++++++++- src/Core/OOTrumble.m | 10 ++- 15 files changed, 230 insertions(+), 83 deletions(-) diff --git a/src/Core/Entities/PlayerEntity.h b/src/Core/Entities/PlayerEntity.h index f8f49bff..d097c079 100644 --- a/src/Core/Entities/PlayerEntity.h +++ b/src/Core/Entities/PlayerEntity.h @@ -795,6 +795,7 @@ typedef enum - (OOWeaponType) weaponForFacing:(OOWeaponFacing)facing; - (OOWeaponType) currentWeapon; +- (Vector) currentLaserOffset; - (void) rotateCargo; diff --git a/src/Core/Entities/PlayerEntity.m b/src/Core/Entities/PlayerEntity.m index de7db618..29314ead 100644 --- a/src/Core/Entities/PlayerEntity.m +++ b/src/Core/Entities/PlayerEntity.m @@ -4453,7 +4453,14 @@ static GLfloat sBaseMass = 0.0; if ([ms isEqual:@"INCOMING_MISSILE"]) { - [self playIncomingMissile]; + if ([self primaryAggressor] != nil) + { + [self playIncomingMissile:HPVectorToVector([[self primaryAggressor] position])]; + } + else + { + [self playIncomingMissile:kZeroVector]; + } [UNIVERSE addMessage:DESC(@"incoming-missile") forCount:4.5]; } @@ -4547,7 +4554,7 @@ static GLfloat sBaseMass = 0.0; { firedMissile = [self launchMine:missile]; if (!replacingMissile) [self removeFromPylon:activeMissile]; - if (firedMissile != nil) [self playMineLaunched]; + if (firedMissile != nil) [self playMineLaunched:[self missileLaunchPosition]]; } else { @@ -4558,7 +4565,7 @@ static GLfloat sBaseMass = 0.0; if (firedMissile != nil) { if (!replacingMissile) [self removeFromPylon:activeMissile]; - [self playMissileLaunched]; + [self playMissileLaunched:[self missileLaunchPosition]]; } } @@ -4772,6 +4779,12 @@ static GLfloat sBaseMass = 0.0; } +- (Vector) currentLaserOffset +{ + return [self laserPortOffset:currentWeaponFacing]; +} + + - (BOOL) fireMainWeapon { int weapon_to_be_fired = [self currentWeapon]; @@ -4783,7 +4796,7 @@ static GLfloat sBaseMass = 0.0; if (weapon_temp / PLAYER_MAX_WEAPON_TEMP >= WEAPON_COOLING_CUTOUT) { - [self playWeaponOverheated]; + [self playWeaponOverheated:[self currentLaserOffset]]; [UNIVERSE addMessage:DESC(@"weapon-overheat") forCount:3.0]; return NO; } @@ -4943,7 +4956,7 @@ static GLfloat sBaseMass = 0.0; - (void) takeEnergyDamage:(double)amount from:(Entity *)ent becauseOf:(Entity *)other { HPVector rel_pos; - double d_forward; + double d_forward, d_right, d_up; BOOL internal_damage = NO; // base chance OOLog(@"player.ship.damage", @"Player took damage from %@ becauseOf %@", ent, other); @@ -4971,8 +4984,11 @@ static GLfloat sBaseMass = 0.0; if ([ent isShip]) [(ShipEntity *)ent doScriptEvent:OOJSID("shipAttackedOther") withArgument:self]; d_forward = dot_product(HPVectorToVector(rel_pos), v_forward); - - [self playShieldHit]; + d_right = dot_product(HPVectorToVector(rel_pos), v_right); + d_up = dot_product(HPVectorToVector(rel_pos), v_up); + Vector relative = make_vector(d_right,d_up,d_forward); + + [self playShieldHit:relative]; // firing on an innocent ship is an offence if ([other isShip]) @@ -5013,7 +5029,7 @@ static GLfloat sBaseMass = 0.0; { internal_damage = ((ranrot_rand() & PLAYER_INTERNAL_DAMAGE_FACTOR) < amount); // base chance of damage to systems energy -= amount; - [self playDirectHit]; + [self playDirectHit:relative]; ship_temperature += (amount / [self heatInsulation]); } [self noteTakingDamage:amount from:other type:damageType]; @@ -5038,7 +5054,7 @@ static GLfloat sBaseMass = 0.0; - (void) takeScrapeDamage:(double) amount from:(Entity *) ent { HPVector rel_pos; - double d_forward; + double d_forward, d_right, d_up; BOOL internal_damage = NO; // base chance if ([self status] == STATUS_DEAD) return; @@ -5055,8 +5071,11 @@ static GLfloat sBaseMass = 0.0; rel_pos = HPvector_subtract(rel_pos, position); // rel_pos is now small d_forward = dot_product(HPVectorToVector(rel_pos), v_forward); - - [self playScrapeDamage]; + d_right = dot_product(HPVectorToVector(rel_pos), v_right); + d_up = dot_product(HPVectorToVector(rel_pos), v_up); + Vector relative = make_vector(d_right,d_up,d_forward); + + [self playScrapeDamage:relative]; if (d_forward >= 0) { forward_shield -= amount; diff --git a/src/Core/Entities/PlayerEntityControls.m b/src/Core/Entities/PlayerEntityControls.m index e9a4b3d3..30dc387f 100644 --- a/src/Core/Entities/PlayerEntityControls.m +++ b/src/Core/Entities/PlayerEntityControls.m @@ -916,7 +916,7 @@ static NSTimeInterval time_last_frame; { if ([self fireMainWeapon]) { - [self playLaserHit:[self shipHitByLaser] != nil]; + [self playLaserHit:([self shipHitByLaser] != nil) offset:[self currentLaserOffset]]; } } diff --git a/src/Core/Entities/PlayerEntitySound.h b/src/Core/Entities/PlayerEntitySound.h index 61df0cb6..4411525d 100644 --- a/src/Core/Entities/PlayerEntitySound.h +++ b/src/Core/Entities/PlayerEntitySound.h @@ -24,7 +24,6 @@ MA 02110-1301, USA. #import "PlayerEntity.h" - @interface PlayerEntity (Sound) - (void) setUpSound; @@ -107,7 +106,7 @@ MA 02110-1301, USA. // Warning sounds - (void) playHostileWarning; - (void) playAlertConditionRed; -- (void) playIncomingMissile; +- (void) playIncomingMissile:(Vector)missileVector; - (void) playEnergyLow; - (void) playDockingDenied; - (void) playWitchjumpFailure; @@ -118,15 +117,15 @@ MA 02110-1301, USA. - (void) playFuelLeak; // Damage sounds -- (void) playShieldHit; -- (void) playDirectHit; -- (void) playScrapeDamage; +- (void) playShieldHit:(Vector)attackVector; +- (void) playDirectHit:(Vector)attackVector; +- (void) playScrapeDamage:(Vector)attackVector; // Weapon sounds -- (void) playLaserHit:(BOOL)hit; -- (void) playWeaponOverheated; -- (void) playMissileLaunched; -- (void) playMineLaunched; +- (void) playLaserHit:(BOOL)hit offset:(Vector)weaponOffset; +- (void) playWeaponOverheated:(Vector)weaponOffset; +- (void) playMissileLaunched:(Vector)weaponOffset; +- (void) playMineLaunched:(Vector)weaponOffset; // Miscellaneous sounds - (void) playEscapePodScooped; diff --git a/src/Core/Entities/PlayerEntitySound.m b/src/Core/Entities/PlayerEntitySound.m index cffef7c7..bde1c965 100644 --- a/src/Core/Entities/PlayerEntitySound.m +++ b/src/Core/Entities/PlayerEntitySound.m @@ -27,6 +27,7 @@ MA 02110-1301, USA. #import "ResourceManager.h" #import "Universe.h" #import "OOSoundSourcePool.h" +#import "OOMaths.h" // Sizes of sound source pools @@ -51,6 +52,14 @@ static OOSoundSource *sBreakPatternSource; static OOSoundSourcePool *sBuySellSourcePool; static OOSoundSource *sAfterburnerSources[2]; +const Vector kInterfaceBeepPosition = { 0.0f, -0.2f, 0.5f }; +const Vector kInterfaceWarningPosition = { 0.0f, -0.2f, 0.4f }; +const Vector kBreakPatternPosition = { 0.0f, 0.0f, 1.0f }; +const Vector kEcmPosition = { 0.2f, 0.6f, -0.1f }; +const Vector kWitchspacePosition = { 0.0f, -0.3f, -0.3f }; +// maybe these should actually track engine positions +const Vector kAfterburner1Position = { -0.1f, 0.0f, -1.0f }; +const Vector kAfterburner2Position = { 0.1f, 0.0f, -1.0f }; @implementation PlayerEntity (Sound) @@ -59,9 +68,16 @@ static OOSoundSource *sAfterburnerSources[2]; [self destroySound]; sInterfaceBeepSource = [[OOSoundSource alloc] init]; + [sInterfaceBeepSource setPosition:kInterfaceBeepPosition]; + sBreakPatternSource = [[OOSoundSource alloc] init]; + [sBreakPatternSource setPosition:kBreakPatternPosition]; + sEcmSource = [[OOSoundSource alloc] init]; + [sEcmSource setPosition:kEcmPosition]; + sHyperspaceSoundSource = [[OOSoundSource alloc] init]; + [sHyperspaceSoundSource setPosition:kWitchspacePosition]; sBuySellSourcePool = [[OOSoundSourcePool alloc] initWithCount:kBuySellSourcePoolSize minRepeatTime:0.0]; sWarningSoundPool = [[OOSoundSourcePool alloc] initWithCount:kWarningPoolSize minRepeatTime:0.0]; @@ -72,7 +88,9 @@ static OOSoundSource *sAfterburnerSources[2]; // Two sources with the same sound are used to simulate looping. OOSound *afterburnerSound = [ResourceManager ooSoundNamed:@"afterburner1.ogg" inFolder:@"Sounds"]; sAfterburnerSources[0] = [[OOSoundSource alloc] initWithSound:afterburnerSound]; + [sAfterburnerSources[0] setPosition:kAfterburner1Position]; sAfterburnerSources[1] = [[OOSoundSource alloc] initWithSound:afterburnerSound]; + [sAfterburnerSources[1] setPosition:kAfterburner2Position]; } @@ -340,6 +358,8 @@ static OOSoundSource *sAfterburnerSources[2]; { if(![sInterfaceBeepSource isPlaying]) { + /* TODO: this should use the scoop position, not the standard + * interface beep position */ [self playInterfaceBeep:@"[scoop]"]; scoopSoundPlayTime = 0.5; } @@ -484,134 +504,134 @@ static OOSoundSource *sAfterburnerSources[2]; - (void) playHostileWarning { - [sWarningSoundPool playSoundWithKey:@"[hostile-warning]" priority:1]; + [sWarningSoundPool playSoundWithKey:@"[hostile-warning]" priority:1 position:kInterfaceWarningPosition]; } - (void) playAlertConditionRed { - [sWarningSoundPool playSoundWithKey:@"[alert-condition-red]" priority:2]; + [sWarningSoundPool playSoundWithKey:@"[alert-condition-red]" priority:2 position:kInterfaceWarningPosition]; } -- (void) playIncomingMissile +- (void) playIncomingMissile:(Vector)missileVector { - [sWarningSoundPool playSoundWithKey:@"[incoming-missile]" priority:3]; + [sWarningSoundPool playSoundWithKey:@"[incoming-missile]" priority:3 position:missileVector]; } - (void) playEnergyLow { - [sWarningSoundPool playSoundWithKey:@"[energy-low]" priority:0.5]; + [sWarningSoundPool playSoundWithKey:@"[energy-low]" priority:0.5 position:kInterfaceWarningPosition]; } - (void) playDockingDenied { - [sWarningSoundPool playSoundWithKey:@"[autopilot-denied]" priority:1]; + [sWarningSoundPool playSoundWithKey:@"[autopilot-denied]" priority:1 position:kInterfaceWarningPosition]; } - (void) playWitchjumpFailure { - [sWarningSoundPool playSoundWithKey:@"[witchdrive-failure]" priority:1.5]; + [sWarningSoundPool playSoundWithKey:@"[witchdrive-failure]" priority:1.5 position:kWitchspacePosition]; } - (void) playWitchjumpMisjump { - [sWarningSoundPool playSoundWithKey:@"[witchdrive-malfunction]" priority:1.5]; + [sWarningSoundPool playSoundWithKey:@"[witchdrive-malfunction]" priority:1.5 position:kWitchspacePosition]; } - (void) playWitchjumpBlocked { - [sWarningSoundPool playSoundWithKey:@"[witch-blocked-by-@]" priority:1.3]; + [sWarningSoundPool playSoundWithKey:@"[witch-blocked-by-@]" priority:1.3 position:kWitchspacePosition]; } - (void) playWitchjumpDistanceTooGreat { - [sWarningSoundPool playSoundWithKey:@"[witch-too-far]" priority:1.3]; + [sWarningSoundPool playSoundWithKey:@"[witch-too-far]" priority:1.3 position:kWitchspacePosition]; } - (void) playWitchjumpInsufficientFuel { - [sWarningSoundPool playSoundWithKey:@"[witch-no-fuel]" priority:1.3]; + [sWarningSoundPool playSoundWithKey:@"[witch-no-fuel]" priority:1.3 position:kWitchspacePosition]; } - (void) playFuelLeak { - [sWarningSoundPool playSoundWithKey:@"[fuel-leak]" priority:0.5]; + [sWarningSoundPool playSoundWithKey:@"[fuel-leak]" priority:0.5 position:kWitchspacePosition]; } -- (void) playShieldHit +- (void) playShieldHit:(Vector)attackVector { - [sDamageSoundPool playSoundWithKey:@"[player-hit-by-weapon]"]; + [sDamageSoundPool playSoundWithKey:@"[player-hit-by-weapon]" position:attackVector]; } -- (void) playDirectHit +- (void) playDirectHit:(Vector)attackVector { - [sDamageSoundPool playSoundWithKey:@"[player-direct-hit]"]; + [sDamageSoundPool playSoundWithKey:@"[player-direct-hit]" position:attackVector]; } -- (void) playScrapeDamage +- (void) playScrapeDamage:(Vector)attackVector { - [sDamageSoundPool playSoundWithKey:@"[player-scrape-damage]"]; + [sDamageSoundPool playSoundWithKey:@"[player-scrape-damage]" position:attackVector]; } -- (void) playLaserHit:(BOOL)hit +- (void) playLaserHit:(BOOL)hit offset:(Vector)weaponOffset { if (hit) { - [sWeaponSoundPool playSoundWithKey:@"[player-laser-hit]" priority:1 expiryTime:0.05]; + [sWeaponSoundPool playSoundWithKey:@"[player-laser-hit]" priority:1.0 expiryTime:0.05 overlap:YES position:weaponOffset]; } else { - [sWeaponSoundPool playSoundWithKey:@"[player-laser-miss]" priority:1 expiryTime:0.05]; + [sWeaponSoundPool playSoundWithKey:@"[player-laser-miss]" priority:1.0 expiryTime:0.05 overlap:YES position:weaponOffset]; } } -- (void) playWeaponOverheated +- (void) playWeaponOverheated:(Vector)weaponOffset { - [sWeaponSoundPool playSoundWithKey:@"[weapon-overheat]" overlap:NO]; + [sWeaponSoundPool playSoundWithKey:@"[weapon-overheat]" overlap:NO position:weaponOffset]; } -- (void) playMissileLaunched +- (void) playMissileLaunched:(Vector)weaponOffset { - [sWeaponSoundPool playSoundWithKey:@"[missile-launched]"]; + [sWeaponSoundPool playSoundWithKey:@"[missile-launched]" position:weaponOffset]; } -- (void) playMineLaunched +- (void) playMineLaunched:(Vector)weaponOffset { - [sWeaponSoundPool playSoundWithKey:@"[mine-launched]"]; + [sWeaponSoundPool playSoundWithKey:@"[mine-launched]" position:weaponOffset]; } - (void) playEscapePodScooped { - [sMiscSoundPool playSoundWithKey:@"[escape-pod-scooped]"]; + [sMiscSoundPool playSoundWithKey:@"[escape-pod-scooped]" position:kInterfaceBeepPosition]; } - (void) playAegisCloseToPlanet { - [sMiscSoundPool playSoundWithKey:@"[aegis-planet]"]; + [sMiscSoundPool playSoundWithKey:@"[aegis-planet]" position:kInterfaceBeepPosition]; } - (void) playAegisCloseToStation { - [sMiscSoundPool playSoundWithKey:@"[aegis-station]"]; + [sMiscSoundPool playSoundWithKey:@"[aegis-station]" position:kInterfaceBeepPosition]; } diff --git a/src/Core/Entities/ShipEntity.h b/src/Core/Entities/ShipEntity.h index 83a1b7c5..94310ff1 100644 --- a/src/Core/Entities/ShipEntity.h +++ b/src/Core/Entities/ShipEntity.h @@ -997,11 +997,13 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q - (BOOL) fireDirectLaserShot:(double)range; - (BOOL) fireDirectLaserDefensiveShot; - (BOOL) fireDirectLaserShotAt:(Entity *)my_target; +- (Vector) laserPortOffset:(OOWeaponFacing)direction; - (BOOL) fireLaserShotInDirection:(OOWeaponFacing)direction; - (void) adjustMissedShots:(int)delta; - (int) missedShots; - (BOOL) firePlasmaShotAtOffset:(double)offset speed:(double)speed color:(OOColor *)color; - (void) considerFiringMissile:(double)delta_t; +- (Vector) missileLaunchPosition; - (ShipEntity *) fireMissile; - (ShipEntity *) fireMissileWithIdentifier:(NSString *) identifier andTarget:(Entity *) target; - (BOOL) isMissileFlagSet; diff --git a/src/Core/Entities/ShipEntity.m b/src/Core/Entities/ShipEntity.m index 04233913..1eb085d1 100644 --- a/src/Core/Entities/ShipEntity.m +++ b/src/Core/Entities/ShipEntity.m @@ -10764,15 +10764,9 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q } -- (BOOL) fireLaserShotInDirection:(OOWeaponFacing)direction +- (Vector) laserPortOffset:(OOWeaponFacing)direction { - double range_limit2 = weaponRange * weaponRange; - GLfloat hit_at_range; - Vector vel = vector_multiply_scalar(v_forward, flightSpeed); - Vector laserPortOffset = kZeroVector; - - last_shot_time = [UNIVERSE getTime]; - + Vector laserPortOffset = kZeroVector; switch (direction) { case WEAPON_FACING_FORWARD: @@ -10792,7 +10786,19 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q laserPortOffset = starboardWeaponOffset; break; } - + return laserPortOffset; +} + + +- (BOOL) fireLaserShotInDirection:(OOWeaponFacing)direction +{ + double range_limit2 = weaponRange * weaponRange; + GLfloat hit_at_range; + Vector vel = vector_multiply_scalar(v_forward, flightSpeed); + Vector laserPortOffset = [self laserPortOffset:direction]; + + last_shot_time = [UNIVERSE getTime]; + ShipEntity *victim = [UNIVERSE firstShipHitByLaserFromShip:self inDirection:direction offset:laserPortOffset gettingRangeFound:&hit_at_range]; [self setShipHitByLaser:victim]; @@ -11044,6 +11050,28 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q } +- (Vector) missileLaunchPosition +{ + Vector start; + // default launching position + start.x = 0.0f; // in the middle + start.y = boundingBox.min.y - 4.0f; // 4m below bounding box + start.z = boundingBox.max.z + 1.0f; // 1m ahead of bounding box + + // custom launching position + start = [shipinfoDictionary oo_vectorForKey:@"missile_launch_position" defaultValue:start]; + + if (start.x == 0.0f && start.y == 0.0f && start.z <= 0.0f) // The kZeroVector as start is illegal also. + { + OOLog(@"ship.missileLaunch.invalidPosition", @"***** ERROR: The missile_launch_position defines a position %@ behind the %@. In future versions such missiles may explode on launch because they have to travel through the ship.", VectorDescription(start), self); + start.x = 0.0f; + start.y = boundingBox.min.y - 4.0f; + start.z = boundingBox.max.z + 1.0f; + } + return start; +} + + - (ShipEntity *) fireMissile { return [self fireMissileWithIdentifier:nil andTarget:[self primaryTarget]]; @@ -11062,21 +11090,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q if ([UNIVERSE getTime] < missile_launch_time) return nil; - // default launching position - start.x = 0.0f; // in the middle - start.y = boundingBox.min.y - 4.0f; // 4m below bounding box - start.z = boundingBox.max.z + 1.0f; // 1m ahead of bounding box - - // custom launching position - start = [shipinfoDictionary oo_vectorForKey:@"missile_launch_position" defaultValue:start]; - - if (start.x == 0.0f && start.y == 0.0f && start.z <= 0.0f) // The kZeroVector as start is illegal also. - { - OOLog(@"ship.missileLaunch.invalidPosition", @"***** ERROR: The missile_launch_position defines a position %@ behind the %@. In future versions such missiles may explode on launch because they have to travel through the ship.", VectorDescription(start), self); - start.x = 0.0f; - start.y = boundingBox.min.y - 4.0f; - start.z = boundingBox.max.z + 1.0f; - } + start = [self missileLaunchPosition]; double throw_speed = 250.0f; diff --git a/src/Core/OOALSoundChannel.h b/src/Core/OOALSoundChannel.h index 28bb552b..f15a1365 100644 --- a/src/Core/OOALSoundChannel.h +++ b/src/Core/OOALSoundChannel.h @@ -32,6 +32,7 @@ SOFTWARE. #import #import "OOOpenALController.h" +#import "OOMaths.h" @class OOSound; @@ -57,6 +58,8 @@ SOFTWARE. - (OOSoundChannel *) next; - (void) setNext:(OOSoundChannel *)next; +// set sound position relative to listener +- (void) setPosition:(Vector) vector; - (BOOL) playSound:(OOSound *)sound looped:(BOOL)loop; - (void)stop; diff --git a/src/Core/OOALSoundChannel.m b/src/Core/OOALSoundChannel.m index f7ecf7c6..08fc01c1 100644 --- a/src/Core/OOALSoundChannel.m +++ b/src/Core/OOALSoundChannel.m @@ -28,6 +28,7 @@ SOFTWARE. #import "OOALSoundChannel.h" #import "OOALSound.h" #import "OOLogging.h" +#import "OOMaths.h" @interface OOSoundChannel (Private) @@ -52,6 +53,9 @@ SOFTWARE. [self release]; self = nil; } + // sources are all relative to listener, defaulting to zero vector + OOAL(alSourcei(_source, AL_SOURCE_RELATIVE, AL_TRUE)); + OOAL(alSource3f(_source, AL_POSITION, 0.0f, 0.0f, 0.0f)); } return self; } @@ -139,6 +143,12 @@ SOFTWARE. } +- (void) setPosition:(Vector) vector +{ + OOAL(alSource3f(_source, AL_POSITION, vector.x, vector.y, vector.z)); +} + + - (BOOL) playSound:(OOSound *)sound looped:(BOOL)loop { if (sound == nil) return NO; diff --git a/src/Core/OOOpenALController.m b/src/Core/OOOpenALController.m index c527c120..2e4c9f65 100644 --- a/src/Core/OOOpenALController.m +++ b/src/Core/OOOpenALController.m @@ -64,6 +64,7 @@ static id sSingleton = nil; { OOLog(kOOLogSoundInitError,@"Error %d creating sound context",error); } + OOAL(alDistanceModel(AL_NONE)); } return self; } diff --git a/src/Core/OOSoundSource.h b/src/Core/OOSoundSource.h index f5d7cff3..c18e49a2 100644 --- a/src/Core/OOSoundSource.h +++ b/src/Core/OOSoundSource.h @@ -44,6 +44,8 @@ OUT OF OR BOOL _loop; uint8_t _repeatCount, _remainingCount; + Vector _position; + BOOL _positional; } + (instancetype) sourceWithSound:(OOSound *)inSound; @@ -69,9 +71,10 @@ OUT OF OR - (void) playSound:(OOSound *)inSound repeatCount:(uint8_t)inCount; - (void) playOrRepeatSound:(OOSound *)inSound; -// Positional audio attributes are ignored in this implementation +// Positional audio attributes are used in this implementation - (void) setPositional:(BOOL)inPositional; - (void) setPosition:(Vector)inPosition; +// *Advanced* positional audio attributes are ignored in this implementation - (void) setVelocity:(Vector)inVelocity; - (void) setOrientation:(Vector)inOrientation; - (void) setConeAngle:(float)inAngle; diff --git a/src/Core/OOSoundSource.m b/src/Core/OOSoundSource.m index 966bcda0..aa1b1ddd 100644 --- a/src/Core/OOSoundSource.m +++ b/src/Core/OOSoundSource.m @@ -27,7 +27,7 @@ SOFTWARE. #import "OOSoundInternal.h" #import "OOLogging.h" - +#import "OOMaths.h" static NSMutableSet *sPlayingSoundSources; @@ -45,6 +45,9 @@ static NSMutableSet *sPlayingSoundSources; self = [self init]; if (!self) return nil; + _positional = NO; + _position = kZeroVector; + [self setSound:inSound]; return self; @@ -133,6 +136,7 @@ static NSMutableSet *sPlayingSoundSources; { _remainingCount = [self repeatCount]; [_channel setDelegate:self]; + [_channel setPosition:_position]; [_channel playSound:[self sound] looped:[self loop]]; [self retain]; } @@ -211,16 +215,32 @@ static NSMutableSet *sPlayingSoundSources; - (void) setPositional:(BOOL)inPositional { - + if (inPositional) + { + _positional = YES; + } + else + { + /* OpenAL doesn't easily do non-positional sounds beyond the + * stereo/mono distinction, but setting the position to the + * zero vector is probably close enough */ + _positional = NO; + [self setPosition:kZeroVector]; + } } - (void) setPosition:(Vector)inPosition { - + _position = inPosition; + if (_channel) + { + [_channel setPosition:_position]; + } } +/* Following not yet implemented */ - (void) setVelocity:(Vector)inVelocity { diff --git a/src/Core/OOSoundSourcePool.h b/src/Core/OOSoundSourcePool.h index 4c8df8f5..8e12a8ce 100644 --- a/src/Core/OOSoundSourcePool.h +++ b/src/Core/OOSoundSourcePool.h @@ -35,7 +35,7 @@ SOFTWARE. #import #import "OOTypes.h" - +#import "OOMaths.h" @interface OOSoundSourcePool: NSObject { @@ -52,6 +52,12 @@ SOFTWARE. + (instancetype) poolWithCount:(uint8_t)count minRepeatTime:(OOTimeDelta)minRepeat; - (id) initWithCount:(uint8_t)count minRepeatTime:(OOTimeDelta)minRepeat; +- (void) playSoundWithKey:(NSString *)key + priority:(float)priority + expiryTime:(OOTimeDelta)expiryTime + overlap:(BOOL)overlap + position:(Vector)position; + - (void) playSoundWithKey:(NSString *)key priority:(float)priority expiryTime:(OOTimeDelta)expiryTime; @@ -59,9 +65,17 @@ SOFTWARE. - (void) playSoundWithKey:(NSString *)key priority:(float)priority; // expiryTime:0.1 +/- 0.5 +- (void) playSoundWithKey:(NSString *)key + priority:(float)priority + position:(Vector)position; // expiryTime:0.1 +/- 0.5 + +- (void) playSoundWithKey:(NSString *)key + position:(Vector)position; // expiryTime:0.1 +/- 0.5 + - (void) playSoundWithKey:(NSString *)key; // priority: 1.0, expiryTime:0.1 +/- 0.5 - (void) playSoundWithKey:(NSString *)key overlap:(BOOL)overlap; // if overlap == NO it waits for key to finish before playing key again +- (void) playSoundWithKey:(NSString *)key overlap:(BOOL)overlap position:(Vector)position; @end diff --git a/src/Core/OOSoundSourcePool.m b/src/Core/OOSoundSourcePool.m index 2846c2c8..8834e0e7 100644 --- a/src/Core/OOSoundSourcePool.m +++ b/src/Core/OOSoundSourcePool.m @@ -103,6 +103,7 @@ typedef struct OOSoundSourcePoolElement priority:(float)priority expiryTime:(OOTimeDelta)expiryTime overlap:(BOOL)overlap + position:(Vector)position { uint8_t slot; OOTimeAbsolute now, absExpiryTime; @@ -137,6 +138,7 @@ typedef struct OOSoundSourcePoolElement if (!overlap) _reserved = slot; // Play and store metadata + [element->source setPosition:position]; [element->source playSound:sound]; element->expiryTime = absExpiryTime; element->priority = priority; @@ -159,7 +161,20 @@ typedef struct OOSoundSourcePoolElement [self playSoundWithKey:key priority:priority expiryTime:expiryTime - overlap:YES]; + overlap:YES + position:kZeroVector]; +} + + +- (void) playSoundWithKey:(NSString *)key + priority:(float)priority + position:(Vector)position +{ + [self playSoundWithKey:key + priority:priority + expiryTime:0.5 + randf() * 0.1 + overlap:YES + position:position]; } @@ -178,14 +193,32 @@ typedef struct OOSoundSourcePoolElement } +- (void) playSoundWithKey:(NSString *)key position:(Vector)position +{ + [self playSoundWithKey:key priority:1.0 position:position]; +} + + - (void) playSoundWithKey:(NSString *)key overlap:(BOOL)overlap { [self playSoundWithKey:key priority:1.0 expiryTime:0.5 - overlap:overlap]; + overlap:overlap + position:kZeroVector]; } + +- (void) playSoundWithKey:(NSString *)key overlap:(BOOL)overlap position:(Vector)position +{ + [self playSoundWithKey:key + priority:1.0 + expiryTime:0.5 + overlap:overlap + position:position]; +} + + @end diff --git a/src/Core/OOTrumble.m b/src/Core/OOTrumble.m index 000376d3..ee28d4a8 100644 --- a/src/Core/OOTrumble.m +++ b/src/Core/OOTrumble.m @@ -29,6 +29,7 @@ MA 02110-1301, USA. #import "ResourceManager.h" #import "OOSound.h" #import "OOStringParsing.h" +#import "OOMaths.h" static void InitTrumbleSounds(void); @@ -987,7 +988,12 @@ static void InitTrumbleSounds(void) static void PlayTrumbleIdle(void) { // Only play idle sound if no trumble is making noise. - if (![sTrumbleSoundSource isPlaying]) [sTrumbleSoundSource playSound:sTrumbleIdleSound]; + if (![sTrumbleSoundSource isPlaying]) + { + // trumble sound from random direction - where's it gone now? + [sTrumbleSoundSource setPosition:OORandomUnitVector()]; + [sTrumbleSoundSource playSound:sTrumbleIdleSound]; + } } @@ -996,6 +1002,8 @@ static void PlayTrumbleSqueal(void) // Play squeal sound if no trumble is currently squealing, but trumping idle sound. if (![sTrumbleSoundSource isPlaying] || [sTrumbleSoundSource sound] == sTrumbleIdleSound) { + // trumble sound from random direction - where's it gone now? + [sTrumbleSoundSource setPosition:OORandomUnitVector()]; [sTrumbleSoundSource playSound:sTrumbleSqealSound]; } }