public static void WriteAudioFile(string key, string saveLocation) { double[,] audioWithHeader = Storage.SignalFromStorage(key); //Storage.SignalStorage.TryGetValue(key, out audioWithHeader); double[,] audioHeaderless = AudioStorageProcessing.RemoveHeader(audioWithHeader, out byte[] header); AudioStorageProcessing.WavSegmentFinder(header, out uint fmtChunkStart, out uint factChunkStart, out uint dataChunkStart, out uint headerSize); ushort channelAmount = ChannelAmount(header, fmtChunkStart); short bytePerSample = (short)(BitsPerSample(header, fmtChunkStart) / 8); uint dataLength = (uint)(audioHeaderless.GetLength(0) * bytePerSample * channelAmount); Conversion.ValueToBitArrayQuick(dataLength, out byte[] dataSegmentSize); for (uint n = dataChunkStart + 4; n < dataChunkStart + 8; n++) { header[n] = dataSegmentSize[n - dataChunkStart - 4]; } byte[] audioByte = TimeDomainToByteArray(audioHeaderless, channelAmount, BitsPerSample(header, fmtChunkStart)); List <byte> list = new List <byte>(header.Length + audioByte.Length); list.AddRange(header); list.AddRange(audioByte); byte[] completeWaveFile = list.ToArray(); string saveFile = key + ".wav"; File.WriteAllBytes(saveLocation + "\\" + saveFile, completeWaveFile); }
/// <summary> /// Synthesis for a bubble. /// Based upon research by /// K. van den Doel, "Physically-based models for liquid sounds," in Proceedings of ICAD 04-Tenth Meeting of the International Conference on Auditory Display, 2004 /// </summary> /// <param name="minRadius">The minimum radius of a water drop.</param> /// <param name="maxRadius">The maximum radius of a water drop.</param> /// <param name="frequencySampling">The sampling rate.</param> /// <param name="amount">The amount of water drops.</param> /// <returns></returns> static public double[,] WaterDrops(double minRadius, double maxRadius, uint frequencySampling, uint amount = 1) { //need to make it so the arrays can overlap each other. instead of uint amount have a param that contain the delays before the next bubble is created, out from the param figure out //their placement in the array System.Diagnostics.Debug.WriteLine("Water Drops " + System.Threading.Thread.CurrentThread.Name); double[] output = new double[0]; for (int i = 0; i < amount; i++) { output = output.Concat(Waterdrop(minRadius, maxRadius, frequencySampling)); } double maxValue = output.Max(); double minValue = output.Min(); for (int m = 0; m < output.Length; m++) //sounds like it is causing a little amount of clipping, save audio data and check it. Data does not indicate that { output[m] = 2 * ((output[m] - minValue) / (maxValue - minValue)) - 1; } double[,] multiChanAudio = new double[output.Length, 1]; for (int i = 0; i < output.Length; i++) { multiChanAudio[i, 0] = output[i]; } byte[] header = WaveHeaderToSignal(output.GetLength(0), frequencySampling, 1); double[,] audio = AudioStorageProcessing.AddWaveToSignal(multiChanAudio, header); return(audio); }
/// <summary> /// Synthesises a marimba tone. /// Based upon research by... /// </summary> /// <param name="tilt">The hit location on the ???. 0.5 is in the middle, 1 and -1 are the edges.</param> /// <param name="velocity"></param> /// <param name="pressure">Controls how quickly the node decay.</param> /// <param name="frequency"></param> /// <param name="frequencySampling"></param> /// <returns></returns> static public double[,] Marimba(float tilt, float velocity, float pressure, uint frequency, uint frequencySampling) { //program it such that if a note is exceeding -1 1 that it get resized to not clip tilt = tilt < -1 ? -1 : tilt; tilt = tilt > 1 ? 1 : tilt; double[] mode = { 0.12 * Math.Sin(1 * tilt * Math.PI), 0.02 * Math.Sin(0.03 + 3.9 * tilt * Math.PI), 0.03 * Math.Sin(0.5 + 9.3 * tilt * Math.PI) }; double[] decay = { -0.0001 * pressure, -0.0001 * pressure, -0.0010 * pressure }; double test = 1; uint index = 0; do { test = Math.Exp(decay[0] * index); index++; } while (test > 0.01); double[] time = new double[index - 1]; for (int i = 0; i < time.Length; i++) { time[i] = i; } double[] note = new double[time.Length]; for (int i = 0; i < note.Length; i++) { note[i] = velocity * ((mode[0] * Math.Exp(decay[0] * time[i]) * Math.Sin(frequency * 2 * Math.PI / frequencySampling * time[i])) + (mode[1] * Math.Exp(decay[1] * time[i]) * Math.Sin(frequency * 2 * 2 * Math.PI / frequencySampling * time[i])) + (mode[2] * Math.Exp(decay[2] * time[i]) * Math.Sin(frequency * 3 * 2 * Math.PI / frequencySampling * time[i]))); } double[,] multiChanAudio = new double[note.Length, 1]; for (int i = 0; i < note.Length; i++) { multiChanAudio[i, 0] = note[i]; } byte[] header = WaveHeaderToSignal(note.Length, frequencySampling, 1); double[,] audio = AudioStorageProcessing.AddWaveToSignal(multiChanAudio, header); return(audio); }
static public double[,] WaterHittingResonSurf(uint samplingRate) { double[] output = new double[0]; output = WaterHittingResonantSurface(samplingRate); double maxValue = output.Max(); double minValue = output.Min(); for (int m = 0; m < output.Length; m++) //sounds like it is causing a little amount of clipping, save audio data and check it. Data does not indicate it does { output[m] = 2 * ((output[m] - minValue) / (maxValue - minValue)) - 1; } double[,] multiChanAudio = new double[output.Length, 1]; for (int i = 0; i < output.Length; i++) { multiChanAudio[i, 0] = output[i]; } byte[] header = WaveHeaderToSignal(output.GetLength(0), samplingRate, 1); double[,] audio = AudioStorageProcessing.AddWaveToSignal(multiChanAudio, header); return(audio); }
public static void LoadAudio(string signalPathwayAndName) { byte[] wav = WaveClass.LoadAudioFile(signalPathwayAndName); string[] seperation = signalPathwayAndName.Split("\\"); string[] nameWithFormat = seperation[seperation.Length - 1].Split("."); string nameWithoutFormat = nameWithFormat[0]; uint headerSize = 44; string currentASCII = ""; uint posistion = 0; do { byte[] wordLooking = { wav[posistion], wav[posistion + 1], wav[posistion + 2], wav[posistion + 3] }; currentASCII = Conversion.ByteArrayToASCII(wordLooking); posistion++; } while (currentASCII != "fmt "); uint fmtChunkStartLocation = --posistion; uint mainHeaderChunkSize = fmtChunkStartLocation; byte[] sizeArray = new byte[4] { wav[fmtChunkStartLocation + 4],//+ 4 to placement because of ID chunk is 4 bytes wav[fmtChunkStartLocation + 5], wav[fmtChunkStartLocation + 6], wav[fmtChunkStartLocation + 7] }; uint fmtChunkSize = 0; Conversion.ByteConverterToInterger(sizeArray, ref fmtChunkSize); sizeArray = new byte[2] { wav[fmtChunkStartLocation + 8], wav[fmtChunkStartLocation + 9] }; fmtChunkSize += 8; uint fmtFormatCode = 0; Conversion.ByteConverterToInterger(sizeArray, ref fmtFormatCode); uint factChunkStartLocation = 0; uint factChuckSize = 0; uint factNumberOfSamples; if (fmtFormatCode != 1) { currentASCII = ""; posistion = 8; do { byte[] wordLooking = { wav[posistion], wav[posistion + 1], wav[posistion + 2], wav[posistion + 3] }; currentASCII = Conversion.ByteArrayToASCII(wordLooking); posistion++; } while (currentASCII != "fact"); factChunkStartLocation = --posistion; } currentASCII = ""; posistion = 8; do { byte[] wordLooking = { wav[posistion], wav[posistion + 1], wav[posistion + 2], wav[posistion + 3] }; currentASCII = Conversion.ByteArrayToASCII(wordLooking); posistion++; } while (currentASCII != "data"); uint dataChunkStartLocation = --posistion; headerSize = dataChunkStartLocation > factChunkStartLocation ? dataChunkStartLocation + 8 : factChunkStartLocation + factChuckSize; byte[] wavHeader = new byte[headerSize]; for (int i = 0; i < headerSize; i++) { wavHeader[i] = wav[i]; } ushort channelAmount = WaveClass.ChannelAmount(wavHeader, fmtChunkStartLocation); uint dataSegmentSize = WaveClass.DataSectionSize(wavHeader, dataChunkStartLocation); short bitsPerSample = WaveClass.BitsPerSample(wavHeader, fmtChunkStartLocation); double[,] audioScaled = WaveClass.ByteArrayToTimeDomain(wav, dataSegmentSize, channelAmount, bitsPerSample, (ulong)wavHeader.Length); double[,] audioWithHeader = AudioStorageProcessing.AddWaveToSignal(audioScaled, wavHeader); Storage.SignalToStorage(audioWithHeader, nameWithoutFormat); }