private (byte[] FormatChunk, RangeHelper.Range DataChunk) ReadChunkRanges(FixtureModel model) { using var stream = model.ToTargetInformation(this.RealFileSystem).FileStream; var riffChunk = Wave.FindRiffChunk(stream); var waveChunk = riffChunk.Bind(r => Wave.FindWaveChunk(stream, r)); var formatChunk = waveChunk.Bind(w => Wave.FindFormatChunk(stream, w)); var dataChunk = waveChunk.Bind(w => Wave.FindDataChunk(stream, w)); var formatSpan = RangeHelper.ReadRange(stream, (RangeHelper.Range)formatChunk); return(formatSpan.ToArray(), (RangeHelper.Range)dataChunk); }
public ValueTask <Recording> ProcessFileAsync(TargetInformation information, Recording recording) { var stream = information.FileStream; var riffChunk = Wave.FindRiffChunk(stream); var waveChunk = riffChunk.Bind(r => Wave.FindWaveChunk(stream, r)); var formatChunk = waveChunk.Bind(w => Wave.FindFormatChunk(stream, w)); var dataChunk = waveChunk.Bind(w => Wave.FindDataChunk(stream, w)); if (formatChunk.IsFail) { this.logger.LogError("Failed to process wave file: {error}", formatChunk); return(new ValueTask <Recording>(recording)); } var formatSpan = RangeHelper.ReadRange(stream, (RangeHelper.Range)formatChunk); var sampleRate = Wave.GetSampleRate(formatSpan); var bitsPerSample = Wave.GetBitsPerSample(formatSpan); var byteRate = Wave.GetByteRate(formatSpan); var channels = Wave.GetChannels(formatSpan); var samples = dataChunk.Map(d => (ulong?)Wave.GetTotalSamples(d, channels, bitsPerSample)); var fileLength = stream.Length; // TODO: replace with rational type from master branch var duration = samples.Map(s => (Rational?)new Rational((uint)samples !, (uint)sampleRate)); return(ValueTask.FromResult(recording with { DurationSeconds = duration.IfFail((Rational?)null), TotalSamples = samples.IfFail((ulong?)null), SampleRateHertz = sampleRate, Channels = (ushort)channels, BitsPerSecond = byteRate * BinaryHelpers.BitsPerByte, BitDepth = (byte)bitsPerSample, FileLengthBytes = (ulong)fileLength, })); }