public static WavFileHeader openWavFile(string fileName, out Int16[] wavSampleData) { WavFileHeader hdr = new WavFileHeader(); wavSampleData = new Int16[] { }; byte[] wavData; try { wavData = File.ReadAllBytes(fileName); if (wavData.Length < 36) { hdr.invalidHeaderMessage = "Error : Input file in incompatible format."; return(hdr); } } catch (Exception ex) { hdr.invalidHeaderMessage = "Error : " + ex.Message; return(hdr); } return(openWavFile(wavData, out wavSampleData)); }
public static WavFileHeader openWavFile(byte[] inputWavData, out Int16[] wavSampleData) { WavFileHeader hdr = new WavFileHeader(); List <byte> wavData = inputWavData.ToList(); wavSampleData = new Int16[] { }; hdr.chunkID = wavData.GetRange(0, 4).ToArray(); // Should be 'RIFF' hdr.chunkSize = BitConverter.ToUInt32(wavData.GetRange(4, 4).ToArray(), 0); hdr.waveStr = wavData.GetRange(8, 4).ToArray(); // Should be 'WAVE' hdr.sc1Id = wavData.GetRange(12, 4).ToArray(); // Should be 'fmt ' hdr.sc1size = BitConverter.ToUInt32(wavData.GetRange(16, 4).ToArray(), 0); // Should be at least 16 hdr.audioFormat = BitConverter.ToUInt16(wavData.GetRange(20, 2).ToArray(), 0); // Should be 1 for PCM hdr.chans = BitConverter.ToUInt16(wavData.GetRange(22, 2).ToArray(), 0); // 1 for mono, 2 for stereo, etc hdr.sampleRate = BitConverter.ToUInt32(wavData.GetRange(24, 4).ToArray(), 0); hdr.byteRate = BitConverter.ToUInt32(wavData.GetRange(28, 4).ToArray(), 0); hdr.blockAlign = BitConverter.ToUInt16(wavData.GetRange(32, 2).ToArray(), 0); hdr.bitsPerSample = BitConverter.ToUInt16(wavData.GetRange(34, 2).ToArray(), 0); //Validate header string chunkID = Encoding.UTF8.GetString(hdr.chunkID, 0, 4); string waveStr = Encoding.UTF8.GetString(hdr.waveStr, 0, 4); string sc1Id = Encoding.UTF8.GetString(hdr.sc1Id, 0, 4); if (chunkID != "RIFF") { hdr.invalidHeaderMessage = "Error : Input file in unsupported format : \"RIFF\" block missing."; } else if (waveStr != "WAVE") { hdr.invalidHeaderMessage = "Error : Input file in unsupported format : \"WAVE\" block missing."; } else if (sc1Id != "fmt ") { hdr.invalidHeaderMessage = "Error : Input file in unsupported format : \"fmt \" block missing."; } else if (hdr.sc1size < 0x10 || hdr.audioFormat != 1) { hdr.invalidHeaderMessage = "Input file in unsupported format : file must be uncompressed PCM."; } else if (hdr.byteRate != hdr.sampleRate * hdr.chans * hdr.bitsPerSample / 8) { hdr.invalidHeaderMessage = "Byte rate in input file is set incorrectly."; } else if (hdr.blockAlign != hdr.bitsPerSample * hdr.chans / 8) { hdr.invalidHeaderMessage = "Block align in input file is set incorrectly."; } else if (hdr.bitsPerSample != 8 && hdr.bitsPerSample != 16) { hdr.invalidHeaderMessage = "Error : unsupported amount of bits per sample (8 or 16 are supported)"; } else { hdr.validHeader = true; } if (!hdr.validHeader) { return(hdr); } if (hdr.chans != 1) { hdr.invalidHeaderMessage = "Input is multi-channel : Will automatically be converted to mono."; } //Validate data header UInt32 index = 0x24 + hdr.sc1size - 0x10; while (true) { try { string subHeaderName = Encoding.UTF8.GetString(wavData.GetRange((int)index, 4).ToArray(), 0, 4); UInt32 subHeaderSize = BitConverter.ToUInt32(wavData.GetRange((int)index + 4, 4).ToArray(), 0); index += 8; if (subHeaderName == "data") { hdr.dataIndex = index; hdr.dataSize = subHeaderSize; List <Int16> buffer = new List <Int16>(); using (MemoryStream ms = new MemoryStream(wavData.GetRange((int)index, (int)subHeaderSize).ToArray())) using (BinaryReader br = new BinaryReader(ms)) { try { while (true) { buffer.Add(br.ReadInt16()); } } catch (EndOfStreamException) { } } wavSampleData = buffer.ToArray(); break; } index += subHeaderSize; } catch { hdr.validHeader = false; hdr.invalidHeaderMessage = "End of file reached without finding a correct \"data\" chunk."; return(hdr); } } //Everything is right. Return hdr. return(hdr); }
public static byte[] encodeBrr(WavFileHeader hdr, Int16[] samples, BrrEncoderOptions options) { List <byte> output = new List <byte>(); byte loopFlag = 0x00; UInt16 loopStart = 0; uint newLoopsize = 0; if (options.loopAddress >= 0) { loopFlag = 0x02; // 0x02 if loop flag is active. loopStart = Convert.ToUInt16(options.loopAddress); } // Optional truncation of input sample UInt32 samplesLength = hdr.dataSize / hdr.blockAlign; // FIXME comprobar qué es esto ¿no se puede utilizar samples.Length? // Adjust amplitude in function of amount of channels samples = adjustAmplitudeOfWavSamples(samples, samplesLength, hdr.chans, hdr.bitsPerSample, options); // Apply resampling if needed applyResampling(ref samples, ref samplesLength, ref newLoopsize, hdr.sampleRate, loopStart, options); // Apply trebble boost filter (gussian lowpass compensation) if requested by user if (options.trebleBoost) { samples = trebleBoostFilter(samples, samplesLength); } //Add zeroes at the beginning if the Amount of PCM samples isn't a multiple of 16 int zeroesToAdd = samples.Length % 16; if (zeroesToAdd != 0) { samples = Enumerable.Repeat((Int16)0, zeroesToAdd).Concat(samples).ToArray(); } //Begin the actual BRR encoding //Initialization needed if any of the first 16 samples isn't zero bool needsInitialBrrBlock = false; if (samples.Length >= 16) { for (int i = 0; i < 16 && !needsInitialBrrBlock; ++i) { needsInitialBrrBlock |= samples[i] != 0; } } else { needsInitialBrrBlock = true; } if (needsInitialBrrBlock) { output = new List <byte>() { loopFlag, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } ; //Encode BRR //Set the truncate size if (options.truncateLen != 0 && output.Count > 0) { options.truncateLen -= 16; } if (options.truncateLen != 0 && (options.truncateLen != samplesLength)) { samplesLength = options.truncateLen; } Int16 p1 = 0; Int16 p2 = 0; BrrEncoderStatistics statistics = new BrrEncoderStatistics(); for (int n = 0; n < samplesLength; n += 16) { byte[] brrChunk = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; //Encode BRR block, tell the encoder if we're at loop point (if loop is enabled), and if we're at end point bool isLoopPoint = options.fixLoopEn && (n == (samplesLength - newLoopsize)); bool isEndPoint = n == samplesLength - 16; Int16[] samplesToCheck = samples.Skip(n).ToArray(); if (samplesToCheck.Length < 16) { samplesToCheck = samplesToCheck.Concat(new Int16[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }).ToArray(); } ADPCMBlockMash(samples.Skip(n).ToArray(), isLoopPoint, isEndPoint, options, statistics, ref p1, ref p2, ref brrChunk); //Set the loop flag if needed brrChunk[0] |= loopFlag; output.AddRange(brrChunk); } //HACKME recover this // if(fix_loop_en) // { // unsigned int k = samples_length - (initial_block ? new_loopsize - 16 : new_loopsize); // printf("Position of the loop within the BRR sample : %u samples = %u BRR blocks.\n", k, k/16); // } // for(int i=0; i<4; i++) // if (FIRstats[i]>0) printf("Filter %u used on %u blocks.\n", i, FIRstats[i]); return(output.ToArray()); }