iPhone Port pt 5 - Sound

The only thing left is to add sound.

Project Modifications

The sound samples for Space Invaders are widely available on the internet, search for them with "MAME Space Invaders sound samples" or something like that. The pack I used had files named 0.wav, 1.wav, etc. The Computer Archeology notes notes have a list of ports and the sounds mapping to them. You'll have to drag them into the project, but should not need to adjust the "Copy" build phase to get them to copy.

Playing a sound in CocoaTouch is fairly easy. You'll have to add the AVFoundation framework to the project.

  1. Select the PhoneInvaders project

  2. Select the PhoneInvaders target

  3. Select Build Phases

  4. Disclose "Link Binary with Libraries"

  5. Click the '+' and add AVFoundation.framework

iOS Add AV Foundation

You'll also want to:

  1. Add #import <AVFoundation/AVFoundation.h> to the top of the SpaceInvadersMachine.h file

  2. Tell the compiler that the SpaceInvadersMachine object implements AVAudioPlayerDelegate by modifying its interface declaration.

  3. Make a class variable for the sound effects.

  4. Make a separate class variable for the UFO sound.

  5. Add variables to save values for the output ports

My SpaceInvadersMachine.h file now looks like this:

   #import <Foundation/Foundation.h>    
   #import <AVFoundation/AVFoundation.h>    
   #include "8080emu.h"

   #define BUTTON_COIN 'c'    
   #define BUTTON_P1_LEFT 'a'    
   #define BUTTON_P1_RIGHT 's'    
   #define BUTTON_P1_FIRE ' '    
   #define BUTTON_P1_START '1'    

   @interface SpaceInvadersMachine : NSObject <AVAudioPlayerDelegate>    
   {    
       State8080   *state;    

       double      lastTimer;    
       double      nextInterrupt;    
       int         whichInterrupt;    

       NSTimer     *emulatorTimer;    

       uint8_t     shift0;         //LSB of Space Invader's external shift hardware    
       uint8_t     shift1;         //MSB    
       uint8_t     shift_offset;   // offset for external shift hardware    

       uint8_t     in_port1;    
       uint8_t     out_port3, out_port5, last_out_port3, last_out_port5;    

       AVAudioPlayer *ufo;    
       AVAudioPlayer *soundeffect;    
   }    

   -(double) timeusec;    

   -(void) ReadFile:(NSString*)filename IntoMemoryAt:(uint32_t)memoffset;    
   -(id) init;    

   -(void) doCPU;    
   -(void) startEmulation;    

   -(void *) framebuffer;    
   -(void) ButtonDown: (uint8_t) key;    
   -(void) ButtonUp: (uint8_t) key;    
   @end    

Modify Machine

The game uses OUT 3 and OUT 5 to communicate to its analog sound circuitry so add them to the OutSpaceInvaders method:


   -(void) OutSpaceInvaders:(uint8_t) port value:(uint8_t)value    
   {    
       switch(port)    
       {    
           case 2:    
               shift_offset = value & 0x7;    
               break;    
           case 3:    
               out_port3 = value;    
               break;    
           case 4:    
               shift0 = shift1;    
               shift1 = value;    
               break;    
           case 5:    
               out_port5 = value;    
               break;    
       }    

   }    

I'll add a routine that watches the output bits to change, and play the sound when they do. I'll use variables to save the previous and current values of port 3 and port 5. When the state of the port bit changes, I'll trigger the sound playing.


   -(void) PlaySounds    
   {    
       if (out_port3 != last_out_port3)    
       {    
           if ( (out_port3 & 0x1) && !(last_out_port3 & 0x1))    
           {    
            //We'll discuss the ufo separately    
           }    

        //Player shot    
           if ( (out_port3 & 0x2) && !(last_out_port3 & 0x2))    
               [self playSoundFile: @"1.wav"];    

        //Player die    
           if ( (out_port3 & 0x4) && !(last_out_port3 & 0x4))    
               [self playSoundFile: @"2.wav"];    

        //Invader explode    
           if ( (out_port3 & 0x8) && !(last_out_port3 & 0x8))    
               [self playSoundFile: @"3.wav"];    

           last_out_port3 = out_port3;    
       }    
       if (out_port5 != last_out_port5)    
       {    
        // Invaders "bomp" sound #1    
           if ( (out_port5 & 0x1) && !(last_out_port5 & 0x1))    
               [self playSoundFile: @"4.wav"];    

        /*.... etc. .......*/    

           last_out_port5 = out_port5;    
       }    
   }    

   -(void) playSoundFile:(NSString*)name    
   {    
       NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:NULL];    
       NSError *error;    
       soundeffect = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];    
       soundeffect.delegate = self;    
       [soundeffect play];    

   }    


The ufo sound repeats the whole time the UFO is visible on the screen. I'll make a class variable to keep the UFO's sound. I'll loop the sound and dispose of it when the game does an OUT 3 with the UFO bit not set. So the UFO code looks like this:

           if ( (out_port3 & 0x1) && !(last_out_port3 & 0x1))    
           {    
               //start UFO    
               NSString *path = [[NSBundle mainBundle] pathForResource:@"0.wav" ofType:NULL];    
               ufo = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];    
               ufo.numberOfLoops=-1;    
               [ufo play];    
            }    
           else if ( !(out_port3 & 0x1) && (last_out_port3 & 0x1))    
           {    
               //stop UFO    
               if (ufo)    
               {    
                   [ufo stop];    
                   [ufo release];    
                   ufo = NULL;    
               }    
           }    

I call [self playSounds] in the code that handles the OUT instruction.

My completed iPhone port with the sound handling is in the github project under iphonePart5-Sound

← Prev: iphone-port-pt-4---touch-handling   Next: iphone-port-pt-6---eye-candy →