public static unsafe int LoadALBufferFromMem(uint bufNumber, byte* samplePointer, uint sampleSize, uint uncompSampleSize = 0) { var wavMem = new MemBufferFileIo(samplePointer, sampleSize); var tmp = wavMem.ToSfVirtualIo(); var sfInfo = new LibsndfileInfo(); var sample = sndFileApi.OpenVirtual(ref tmp, LibsndfileMode.Read, ref sfInfo, &wavMem); if(sample == IntPtr.Zero) { Sys.DebugLog(LOG_FILENAME, "Error: can't load sample #{0:D3} from sample block!", bufNumber); Sys.DebugLog(LOG_FILENAME, $"Libsndfile error: {sndFileApi.Error(IntPtr.Zero):G} ({sndFileApi.ErrorString(IntPtr.Zero)})"); return -1; } // Uncomp_sample_size explicitly specifies amount of raw sample data // to load into buffer. It is only used in TR4/5 with ADPCM samples, // because full-sized ADPCM sample contains a bit of silence at the end, // which should be removed. That's where uncomp_sample_size comes into // business. // Note that we also need to compare if uncomp_sample_size is smaller // than native wav length, because for some reason many TR5 uncomp sizes // are messed up and actually more than actual sample size. var realSize = sfInfo.Frames * sizeof(ushort); if (uncompSampleSize == 0 || realSize < uncompSampleSize) { uncompSampleSize = (uint)realSize; } // We need to change buffer size, as we're using floats here. if (AUDIO_OPENAL_FLOAT) uncompSampleSize = (uncompSampleSize / sizeof(ushort)) * sizeof(float); else uncompSampleSize = uncompSampleSize / sizeof(ushort) * sizeof(short); // Find out sample format and load it correspondingly. // Note that with OpenAL, we can have samples of different formats in same level. var result = FillALBuffer(bufNumber, sample, uncompSampleSize, sfInfo); sndFileApi.Close(sample); return result ? 0 : -3; // Zero means success }
/// <summary> /// Wad loading /// </summary> private unsafe bool loadWad(byte index, string filename) { if (index >= TR_AUDIO_STREAM_WAD_COUNT) { ConsoleInfo.Instance.Warning(Strings.SYSWARN_WAD_OUT_OF_BOUNDS, TR_AUDIO_STREAM_WAD_COUNT); return false; } FileStream wadFile; try { wadFile = File.OpenRead(filename); } catch { ConsoleInfo.Instance.Warning(Strings.SYSWARN_FILE_NOT_FOUND, filename); return false; } var trackName = ""; uint offset = 0; uint length = 0; using (var br = Helper.CreateInstance<BinaryReader>(wadFile, Encoding.UTF8, true)) { br.BaseStream.Position = index * TR_AUDIO_STREAM_WAD_STRIDE; trackName = br.ParseString(TR_AUDIO_STREAM_WAD_NAMELENGTH, true); length = br.ReadUInt32(); offset = br.ReadUInt32(); br.BaseStream.Position = offset; } if ((IntPtr) wadBuf != IntPtr.Zero) { Marshal.FreeHGlobal((IntPtr) wadBuf); } if ((IntPtr)wadMemIo != IntPtr.Zero) { Marshal.FreeHGlobal((IntPtr)wadMemIo); } wadBuf = (byte*)Marshal.AllocHGlobal((int) length); var buf = new byte[(int)length]; wadFile.Read(buf, 0, (int) length); Marshal.Copy(buf, 0, (IntPtr)wadBuf, (int)length); wadMemIo = (MemBufferFileIo*) Marshal.AllocHGlobal(sizeof (MemBufferFileIo)); var s = new MemBufferFileIo(wadBuf, (int) length); Marshal.StructureToPtr(s, (IntPtr)wadMemIo, false); var vio = wadMemIo->ToSfVirtualIo(); if ((sndFile = sndFileApi.OpenVirtual(ref vio, LibsndfileMode.Read, ref sfInfo, wadMemIo)) == IntPtr.Zero) { ConsoleInfo.Instance.Warning(Strings.SYSWARN_WAD_SEEK_FAILED, offset); ConsoleInfo.Instance.AddLine( $"Libsndfile error: {sndFileApi.Error(IntPtr.Zero):G} ({sndFileApi.ErrorString(IntPtr.Zero)})", FontStyle.ConsoleWarning); method = TR_AUDIO_STREAM_METHOD.Unknown; return false; } ConsoleInfo.Instance.Notify(Strings.SYSNOTE_WAD_PLAYING, filename, offset, length); ConsoleInfo.Instance.Notify(Strings.SYSNOTE_TRACK_OPENED, trackName, sfInfo.Channels, sfInfo.SampleRate); if (AUDIO_OPENAL_FLOAT) format = sfInfo.Channels == 1 ? ALFormat.MonoFloat32Ext : ALFormat.StereoFloat32Ext; else format = sfInfo.Channels == 1 ? ALFormat.Mono16 : ALFormat.Stereo16; rate = sfInfo.SampleRate; return true; // Success! }