public bool LoadSong(string filename, List <BpmChangeEvent> bpmChanges) { IsFinished = false; streamHandle = SDL_mixer.Mix_LoadMUS(filename); Globals.BpmEvents = bpmChanges; Globals.BpmEvents = Globals.BpmEvents.OrderBy(x => x.StartBeat).ToList(); for (int i = 0; i < Globals.BpmEvents.Count; i++) { if (i > 0) { Globals.BpmEvents[i].StartSeconds = (Globals.BpmEvents[i].StartBeat - Globals.BpmEvents[i - 1].StartBeat) / Globals.BpmEvents[i - 1].BPM * 60 + Globals.BpmEvents[i - 1].StartSeconds; } } //SongBpm = bpm; // Globals.CurrentBpm = Globals.BpmEvents[0].BPM; // create hooks here SDL_mixer.Mix_HookMusic(MixDelegate, IntPtr.Zero); SDL_mixer.Mix_HookMusicFinished(FinishedDelegate); // Use the left channel for grabbing this info for now. // Is this correct? I'm not sure. IntPtr leftChannelMixChunk = SDL_mixer.Mix_GetChunk(leftChannel); SDL_mixer.Mix_QuerySpec(out frequency, out format, out channels); unsafe { byte *pLeftChannel = (byte *)leftChannelMixChunk.ToPointer(); if (pLeftChannel != null) { /* * typedef struct Mix_Chunk { * int allocated; * Uint8 *abuf; * Uint32 alen; * Uint8 volume; * } Mix_Chunk; * get the value of alen within this struct * refer to https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC85 for more details */ SongLengthBytes = *(pLeftChannel + sizeof(int) + sizeof(byte)); SongLengthSec = GetCurrentSec(SongLengthBytes); } } return(streamHandle == IntPtr.Zero ? false : true); }