/// <summary> /// Get decoded audio track for the BGM using a specified samplerate. /// could probably work with different samplerates but i don't know why you'd try /// </summary> /// <param name="dstFreq"></param> /// <param name="track">The type of Audio Track</param> /// <returns>Signed 16-Bit PCM audio</returns> public short[] getAudioTrackPcm(int dstFreq, PPMAudioTrack track) { var srcPcm = Decode(track); var srcFreq = 8192; double soundspeed = Flipnote.BGMRate; double framerate = Flipnote.Framerate; if (track == PPMAudioTrack.BGM) { var bgmAdjust = (1.0 / soundspeed) / (1.0 / framerate); srcFreq = ((int)(srcFreq * bgmAdjust)); } if ((int)srcFreq != dstFreq) { return(pcmResampleNearestNeighbour(srcPcm, srcFreq, dstFreq)); } return(srcPcm); }
/// <summary> /// Get decoded audio track for a given track /// </summary> /// <param name="track">Which type of Audio Track to decode</param> /// <returns>Signed 16-Bit PCM audio</returns> private short[] Decode(PPMAudioTrack track) { _SoundData sounds = Flipnote.Audio.SoundData; byte[] src = null; switch (track) { case PPMAudioTrack.BGM: src = sounds.RawBGM; break; case PPMAudioTrack.SE1: src = sounds.RawSE1; break; case PPMAudioTrack.SE2: src = sounds.RawSE2; break; case PPMAudioTrack.SE3: src = sounds.RawSE3; break; default: src = sounds.RawBGM; break; } var srcSize = src.Length; var dst = new short[srcSize * 2]; var srcPtr = 0; var dstPtr = 0; var sample = 0; step_index = 0; var predictor = 0; var lowNibble = true; while (srcPtr < srcSize) { // switch between high and low nibble each loop iteration // increments srcPtr after every high nibble if (lowNibble) { sample = src[srcPtr] & 0xF; } else { sample = src[srcPtr++] >> 4; } lowNibble = !lowNibble; var step = ADPCM_STEP_TABLE[step_index]; var diff = step >> 3; if ((sample & 1) != 0) { diff += step >> 2; } if ((sample & 2) != 0) { diff += step >> 1; } if ((sample & 4) != 0) { diff += step; } if ((sample & 8) != 0) { diff = -diff; } predictor += diff; predictor = Utils.NumClamp(predictor, -32768, 32767); step_index += IndexTable[sample]; step_index = Utils.NumClamp(step_index, 0, 88); dst[dstPtr++] = (short)predictor; } return(dst); }