All files / src/store/features/soundfx soundfxMiddleware.ts

51.72% Statements 30/58
50% Branches 15/30
44.44% Functions 4/9
50% Lines 28/56

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 1042x                 2x 2x 2x 2x 2x 2x     2x 2x               2x 2x 2x                                                 2x       2x             2x 3x       3x 1x 1x 1x       2x     2x           2x   2x       1x 1x             3x     2x  
import {
  playTone,
  stopTone,
  playBuffer,
  stopBuffer,
  decodeAudioData,
} from "renderer/lib/soundfx/soundfx";
import { Dispatch, Middleware } from "@reduxjs/toolkit";
import { RootState } from "store/storeTypes";
import musicActions from "store/features/music/musicActions";
import navigationActions from "store/features/navigation/navigationActions";
import actions from "./soundfxActions";
import { soundSelectors } from "store/features/entities/entitiesSelectors";
import { assetPath } from "shared/lib/helpers/assets";
import API from "renderer/lib/api";
import { SoundAsset } from "shared/lib/resources/types";
 
let oscillator: OscillatorNode | undefined = undefined;
let bufferSource: AudioBufferSourceNode | undefined = undefined;
 
function initMusic() {
  window.removeEventListener("click", initMusic);
  window.removeEventListener("keydown", initMusic);
}
 
// Initialise audio on first click
window.addEventListener("click", initMusic);
window.addEventListener("keydown", initMusic);
window.addEventListener("blur", pause);
 
function play(filename: string) {
  const url = `gbs://app-assets/soundfx/${filename}`;
  fetch(url)
    .then((response) => response.arrayBuffer())
    .then(decodeAudioData)
    .then((data) => {
      bufferSource = playBuffer(data);
    });
}
 
async function playSound(sound: SoundAsset, effectIndex: number) {
  const filename = assetPath("sounds", sound);
 
  if (sound.type === "wav") {
    API.soundfx.playWav(filename);
  } else if (sound.type === "vgm") {
    API.soundfx.playVGM(filename);
  } else if (sound.type === "fxhammer") {
    API.soundfx.playFXHammer(filename, effectIndex);
  }
}
 
function pause() {
  Iif (oscillator) {
    stopTone(oscillator);
    oscillator = undefined;
  }
  Iif (bufferSource) {
    stopBuffer(bufferSource);
    bufferSource = undefined;
  }
}
 
const soundfxMiddleware: Middleware<Dispatch, RootState> =
  (store) => (next) => (action) => {
    Iif (actions.playSoundFxBeep.match(action)) {
      store.dispatch(musicActions.pauseMusic());
      pause();
      play(`effect_beep_${action.payload.pitch}.mp3`);
    } else if (actions.playSoundFxTone.match(action)) {
      store.dispatch(musicActions.pauseMusic());
      pause();
      oscillator = playTone(
        action.payload.frequency,
        action.payload.duration * 1000,
      );
    } else Iif (actions.playSoundFxCrash.match(action)) {
      store.dispatch(musicActions.pauseMusic());
      play("effect_crash.mp3");
    } else Iif (actions.playSoundFx.match(action)) {
      const state = store.getState();
      const sound = soundSelectors.selectById(state, action.payload.effect);
      if (sound) {
        playSound(sound, action.payload.effectIndex);
      }
    } else Iif (actions.pauseSoundFx.match(action)) {
      pause();
    } else if (
      musicActions.playMusic.match(action) ||
      musicActions.pauseMusic.match(action)
    ) {
      pause();
    } else Iif (
      navigationActions.setSection.match(action) ||
      navigationActions.setNavigationId.match(action)
    ) {
      pause();
    }
 
    return next(action);
  };
 
export default soundfxMiddleware;