public void Pause(int channel = -1) { if (channel == MusicChannel) { SDL_mixer.Mix_PauseMusic(); } else { SDL_mixer.Mix_Pause(channel); } }
public override void Update(FPoint pos) { lastPos = pos; List <int> cleanup = new List <int>(); foreach (var it in playback) { int channel = it.Key; Playback play = it.Value; if (play.Finished) { cleanup.Add(channel); continue; } if (play.Location.X == 0 && play.Location.Y == 0) { continue; } float v = CalcDist(pos, play.Location) / soundFallOff; if (play.Loop) { if (v < 1.0f && play.Paused) { SDL_mixer.Mix_Resume(channel); play.Paused = false; } else if (v > 1.0f && !play.Paused) { SDL_mixer.Mix_Pause(channel); play.Paused = true; continue; } } v = Math.Min(Math.Max(v, 0.0f), 1.0f); byte dist = (byte)(255.0f * v); SetChannelPosition(channel, 0, dist); } while (cleanup.Count > 0) { int channel = cleanup[0]; cleanup.RemoveAt(0); if (playback.TryGetValue(channel, out Playback play)) { playback.Remove(channel); if (channels.TryGetValue(play.VirtualChannel, out int vcit)) { channels.Remove(play.VirtualChannel); } } } }
public override void PauseAll() { SDL_mixer.Mix_Pause(-1); SDL_mixer.Mix_PauseMusic(); }
/** * Used to start the GUI event loop using the SDL window to poll for events. When an event is * received, the keyboard state is read and the OnTick event is fired. After the event completes * a frame and/or audio can be rendered/played based on the values set in the OnTick event args. * * This is a BLOCKING call; the event loop will continue to be polled until (1) the user uses * the platform specific key combination or GUI action to close the window or (2) the OnTick * event arguments has ShouldQuit set to true. */ public void StartLoop() { // Used to keep track of the time elapsed in each loop iteration. This is used to // notify the OnTick handlers so they can update their simulation, as well as throttle // the update loop to targetTicskHz if needed. var stopwatch = new Stopwatch(); // Structure used to pass data to and from the OnTick handlers. We initialize it once // outside of the loop to avoid eating a ton of memory putting GC into a tailspin. var tickEventArgs = new GUITickEventArgs(); // The SDL event polled for in each iteration of the loop. SDL.SDL_Event sdlEvent; while (true) { stopwatch.Restart(); tickEventArgs.KeyDown = null; tickEventArgs.ShouldBreak = false; while (SDL.SDL_PollEvent(out sdlEvent) != 0) { switch (sdlEvent.type) { // e.g. Command + Q, ALT+F4, or clicking X... case SDL.SDL_EventType.SDL_QUIT: // Break out of the SDL event loop, which will close the program. return; case SDL.SDL_EventType.SDL_KEYDOWN: tickEventArgs.KeyDown = sdlEvent.key.keysym.sym; UpdateKeys(tickEventArgs, sdlEvent.key.keysym.sym, true); // If the break/pause or 9 key is pressed, set a flag indicating the // emulator's should activate the interactive debugger. if (sdlEvent.key.keysym.sym == SDL.SDL_Keycode.SDLK_PAUSE || sdlEvent.key.keysym.sym == SDL.SDL_Keycode.SDLK_9) { tickEventArgs.ShouldBreak = true; } break; case SDL.SDL_EventType.SDL_KEYUP: UpdateKeys(tickEventArgs, sdlEvent.key.keysym.sym, false); break; } } // Update the event arguments that will be sent with the event handler. tickEventArgs.ShouldRender = false; tickEventArgs.ShouldPlaySounds = false; tickEventArgs.SoundEffects.Clear(); // Delegate out to the event handler so work can be done. if (OnTick != null) { OnTick(tickEventArgs); } // We only want to re-render if the frame buffer has changed since last time because // the SDL_RenderPresent method is relatively expensive. if (tickEventArgs.ShouldRender && tickEventArgs.FrameBuffer != null) { // Render screen from the updated the frame buffer. // NOTE: The electron beam scans from left to right, starting in the upper left corner // of the CRT when it is in 4:3 (landscape), which is how the framebuffer is stored. // However, since the CRT in the cabinet is rotated left (-90 degrees) to show the game // in 3:4 (portrait) we need to perform the rotation of points below by starting in the // bottom left corner of the window and drawing upwards, ending on the top right. // Clear the screen. SDL.SDL_SetRenderDrawColor(_renderer, 0, 0, 0, 0); SDL.SDL_RenderClear(_renderer); var bits = new System.Collections.BitArray(tickEventArgs.FrameBuffer); var x = 0; var y = SpaceInvaders.RESOLUTION_WIDTH - 1; for (var i = 0; i < bits.Length; i++) { if (bits[i]) { // The CRT is black/white and the framebuffer is 1-bit per pixel. // A transparent overlay added "colors" to areas of the CRT. These // are the approximate y locations of each area/color of the overlay: if (y >= 182 && y <= 223) { SDL.SDL_SetRenderDrawColor(_renderer, 0, 255, 0, 255); // Green - player and shields } else if (y >= 33 && y <= 55) { SDL.SDL_SetRenderDrawColor(_renderer, 255, 0, 0, 255); // Red - UFO } else { SDL.SDL_SetRenderDrawColor(_renderer, 255, 255, 255, 255); // White - Everything else } SDL.SDL_RenderDrawPoint(_renderer, x, y); } y--; if (y == -1) { y = SpaceInvaders.RESOLUTION_WIDTH - 1; x++; } if (x == SpaceInvaders.RESOLUTION_HEIGHT) { break; } } SDL.SDL_RenderPresent(_renderer); } // Handle playing sound effects. if (soundEffects != null && tickEventArgs.ShouldPlaySounds && tickEventArgs.SoundEffects != null) { foreach (var sfx in tickEventArgs.SoundEffects) { var pointer = soundEffects[sfx]; // Result of Mix_PlayChannel, which indicates the channel the sound is playing on. // -1 indicates an error. var playChannelResult = -1; switch (sfx) { // The UFO sound effect loops until the UFO disappears or is destroyed. case SoundEffect.UFO_Start: playChannelResult = SDL_mixer.Mix_PlayChannel(AUDIO_CHANNEL_UFO, pointer, AUDIO_INFINITE_LOOP); break; case SoundEffect.UFO_Stop: { SDL_mixer.Mix_Pause(AUDIO_CHANNEL_UFO); // Mix_Pause doesn't return a channel or error code. Ensure we don't leave as -1. playChannelResult = AUDIO_CHANNEL_UFO; break; } case SoundEffect.InvaderMove1: case SoundEffect.InvaderMove2: case SoundEffect.InvaderMove3: case SoundEffect.InvaderMove4: playChannelResult = SDL_mixer.Mix_PlayChannel(AUDIO_CHANNEL_INVADER_MOVEMENT, pointer, AUDIO_NO_LOOP); break; default: playChannelResult = SDL_mixer.Mix_PlayChannel(AUDIO_CHANNEL_COMMON, pointer, AUDIO_NO_LOOP); break; } if (playChannelResult == -1) { Console.WriteLine("Error playing sound effect {0}. SDL Error: {1}", sfx, SDL.SDL_GetError()); } } } // See if we need to delay to keep locked to ~ targetTicskHz. if (stopwatch.Elapsed.TotalMilliseconds < (1000 / _targetTicksHz)) { var delay = (1000 / _targetTicksHz) - stopwatch.Elapsed.TotalMilliseconds; SDL.SDL_Delay((uint)delay); } // If the event handler indicated we should quit, then stop. if (tickEventArgs.ShouldQuit) { return; } } }