1

I am developing a game where an SKAudioNode plays the game music. When the player starts a new game, I want the music to fade in so I wrote the following code:

SKAudioNode *SFXNode = [[SKAudioNode alloc] initWithfile:@"GameMusic.mp3"];
[SFXNode runAction:[SKAction changeVolumeTo:0 duration:0]];
SFXNode.positional = NO;
[self addChild:SFXNode];
[SFXNode runAction:[SKAction changeVolumeTo:1 duration:1]];

However, when the scene initiates, the music plays at full volume for a split second, then it mutes and fades back in as it is supposed to. Does anyone have any idea why this is happening? (The music is only full volume after the user has triggered the modal segue to the scene, but before it has been displayed on the screen. As soon as the scene is displayed the music fades in normally). Also, the music does seem to be positional: as the player moves about in the scene the volume changes which I do not want happening. Solutions top either of these problems are much appreciated. Thank you!

1 Answers1

1

This is because your volume change is happening after the audio is sent to the audio buffer. You need to do reset the volume before update happens. Now you can't do this as soon as you create the audio, you need to do it after it is added to the AudioEngine, so I would recommend doing this when your scene moves to the view (in the didMoveToView function).

The code to actually change the volume should be something like

((AVAudioMixerNode *)SFXNode.avAudioNode).volume = 0 but I would recommend checking if avAudioNode exists first and that it does conform to the AVAudioMixerNode protocol

Knight0fDragon
  • 15,949
  • 2
  • 20
  • 41
  • However the cast type has to be a pointer in this case - I have suggested an edit. – L. Richmond Jan 22 '18 at 20:57
  • Any idea why the audio is positional? – L. Richmond Jan 22 '18 at 20:57
  • Yeah I stopped using ObjC a long time ago and switched to Swift, so I don’t have to worry about silly pointer markers lol. As for positional audio, it is a setting you have to play with. I do not deal with SKAudioNode that much, so I recommend checking the docs. – Knight0fDragon Jan 22 '18 at 21:27
  • I also had to include the AVKit framework to my project for this to work. Lol I should probably switch to swift too it sounds so much easier – L. Richmond Jan 22 '18 at 21:43
  • I have the exact same problem. I was hoping I could use the same solution but my node.avAudioNode is not an AVAudioMixerNode. I tried explicitly adding in AVKit and AVFoundation but no luck. Anything else you need that isn't mentioned already? – Dennis Mar 28 '18 at 14:52
  • @Dennis it should be a subclass of it – Knight0fDragon Mar 28 '18 at 14:53
  • guard let am = s.avAudioNode as? AVAudioMixerNode else { print ( "Not a mixer node." ) return } doesn't pass the guard.. – Dennis Mar 28 '18 at 14:57
  • @Dennis did you check to see if s.avAudioNode itself is not null? – Knight0fDragon Mar 28 '18 at 14:59
  • Yeah if I print it in the debugger it: (AVAudioNode?) $R0 = 0x00000001d0202a60 { ObjectiveC.NSObject = {} } – Dennis Mar 28 '18 at 15:02
  • p type(of:s.avAudioNode) (AVAudioNode?.Type) $R4 = AVAudioNode? – Dennis Mar 28 '18 at 15:04
  • Add this above your guard: `guard let _ = s.avAudioNode else { print ( "avAudioNode is nil." ) return }` – Knight0fDragon Mar 28 '18 at 15:05
  • Included frameworks by going to the project build phases and adding AVKit/AVFoundation to the list of linked libraries. I now see them in the project frameworks folder as well. – Dennis Mar 28 '18 at 15:07
  • It should be built into the SpriteKit Framework in swift – Knight0fDragon Mar 28 '18 at 15:08
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/167744/discussion-between-dennis-and-knight0fdragon). – Dennis Mar 28 '18 at 15:10