The only thing left is to add sound.
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.
Select the PhoneInvaders project
Select the PhoneInvaders target
Select Build Phases
Disclose "Link Binary with Libraries"
Click the '+' and add AVFoundation.framework
You'll also want to:
Add #import <AVFoundation/AVFoundation.h>
to the top of the SpaceInvadersMachine.h file
Tell the compiler that the SpaceInvadersMachine object implements AVAudioPlayerDelegate by modifying its interface declaration.
Make a class variable for the sound effects.
Make a separate class variable for the UFO sound.
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
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 →Post questions or comments on Twitter @realemulator101, or if you find issues in the code, file them on the github repository.