public FFTPlayer(IAudioReader reader) { _Reader = reader; _RawDataReader = FFTDataReaderFactory.CreateForFormat(reader.Provider.Format); int bufferLength = reader.BufferLength; Buffer = new float[bufferLength]; Buffer2 = new float[bufferLength]; _Buffer3 = new double[bufferLength]; UIntPtr allocSize = (UIntPtr)(8 * (uint)bufferLength); _Input = FFTW.Malloc(allocSize); _Output = FFTW.Malloc(allocSize); _Plan = FFTW.PlanDft1D(bufferLength, _Input, _Output, -1, 0 /* FFTW_MEASURE */); for (int i = 0; i < bufferLength; ++i) { _Input[i].Imaginary = 0; //Clear only imaginary } _WindowFunction = new float[bufferLength]; float sigma = bufferLength / 2 / WindowRange; int offset = bufferLength / 2; for (int i = 0; i < bufferLength; ++i) { float x = (i - offset); _WindowFunction[i] = (float)Math.Exp(-x * x / 2 / sigma / sigma); } }
private String thePath; // Path of this file // ------------------------------------------------------------------------------------------ /// <summary> /// Constructor /// </summary> /// <param name="path">Path of the file to be parsed</param> public AudioFileReader(String path) { thePath = path; theFactory = AudioReaderFactory.GetInstance(); audioData = theFactory.GetDataReader(path); metaData = theFactory.GetMetaReader(path, audioData); }
public static IAudioFormat OpenFile(string path) { FileType type = AudioInfo.GetFileTypeFromName(path); IAudioReader reader = AudioInfo.Containers[type].GetReader(); using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read)) { return(reader.ReadFormat(stream)); } }
private void tsbOpen_Click(object sender, EventArgs e) { if (ofdAudio.ShowDialog() == DialogResult.OK) { string fileName = ofdAudio.FileName; IAudioReader arw = null; switch (Path.GetExtension(fileName.ToLower())) { case ".avi": arw = new AviReader(File.Open(fileName, FileMode.Open, FileAccess.ReadWrite)); if (!((AviReader)arw).HasAudio) { MessageBox.Show(string.Format("'{0}' file is not contains audio data", fileName)); return; } break; case ".au": case ".snd": arw = new AuReader(File.OpenRead(fileName)); break; case ".wav": arw = new WaveReadWriter(File.Open(fileName, FileMode.Open, FileAccess.ReadWrite)); break; case ".mp3": arw = new Mp3ReadWriter(File.Open(fileName, FileMode.Open, FileAccess.ReadWrite)); break; default: arw = new DsReader(fileName); if (!((DsReader)arw).HasAudio) { MessageBox.Show(string.Format("'{0}' file is not contains audio data", fileName)); return; } break; //FormatDialog fd = new FormatDialog(false); //if (fd.ShowDialog() == DialogResult.OK) //{ // arw = new RawReadWriter(stream, fd.Format); // break; //} //else //{ // return; //} } rp.Open(arw); } }
public void Play(IAudioReader wr, AudioEffect af) { //string fileName = @"c:\Wint\audio\NAudio-1-3\Source Code\MixDiff\bin\Debug\Windows XP Startup.wav";//1,16,8000.wav//G:\10\mp3\2,16,44100.wav //WaveReader wr = new WaveReader(File.OpenRead(fileName)); IntPtr format = wr.ReadFormat(); WaveFormat wf1 = AudioCompressionManager.GetWaveFormat(format); Console.WriteLine("{0},{1},{2}-{3}", wf1.nChannels, wf1.wBitsPerSample, wf1.nSamplesPerSec, wf1.wFormatTag); byte[] data = wr.ReadData(); if (wf1.wFormatTag != 1) { IntPtr formatNew = IntPtr.Zero; byte[] dataNew = null; AudioCompressionManager.ToPcm(format, data, ref formatNew, ref dataNew); format = formatNew; data = dataNew; WaveFormat wf2 = AudioCompressionManager.GetWaveFormat(format); Console.WriteLine("{0},{1},{2}-{3}", wf2.nChannels, wf2.wBitsPerSample, wf2.nSamplesPerSec, wf2.wFormatTag); } else if (wf1.wBitsPerSample != 16) { WaveFormat wf = AudioCompressionManager.GetWaveFormat(format); IntPtr formatNew = AudioCompressionManager.GetPcmFormat(wf.nChannels, 16, wf.nSamplesPerSec); byte[] dataNew = AudioCompressionManager.Convert(format, formatNew, data, false); format = formatNew; data = dataNew; WaveFormat wf2 = AudioCompressionManager.GetWaveFormat(format); Console.WriteLine("{0},{1},{2}-{3}", wf2.nChannels, wf2.wBitsPerSample, wf2.nSamplesPerSec, wf2.wFormatTag); } //wr.Close(); if (af != null) { bool hasProcessInPlace = af.HasProcessInPlace; //af.GetSupportedOutputFormats(); GCHandle src = GCHandle.Alloc(data, GCHandleType.Pinned); IntPtr formatPtr = src.AddrOfPinnedObject(); bool res = af.ProcessInPlace(format, data); src.Free(); if (!res) { MessageBox.Show("Unable to convert the audio data"); return; } } if (plex.State != DeviceState.Closed) { plex.ClosePlayer(); } Console.WriteLine(plex.State); plex.OpenPlayer(format); plex.AddData(data); plex.StartPlay(); }
private void Open() { if (ofdAudio.ShowDialog() == DialogResult.OK) { if (ar != null) { ar.Close(); ar = null; } string fileName = ofdAudio.FileName; ar = null; switch (Path.GetExtension(fileName.ToLower())) { case ".vox": ar = GetVoxReader(fileName, 8000); break; case ".avi": ar = new AviReader(File.OpenRead(fileName)); if (!((AviReader)ar).HasAudio) { MessageBox.Show(string.Format("'{0}' file is not contains audio data", fileName)); return; } break; case ".au": case ".snd": ar = new AuReader(File.OpenRead(fileName)); break; case ".wav": ar = new WaveReader(File.OpenRead(fileName)); break; case ".mp3": ar = new Mp3Reader(File.OpenRead(fileName)); break; default: ar = new DsReader(fileName); if (!((DsReader)ar).HasAudio) { ar = null; MessageBox.Show(string.Format("'{0}' file is not contains audio data", fileName)); } break; } Play(); UpdateToolBar(); } }
private void FormFourier_FormClosed(object sender, FormClosedEventArgs e) { if (_Reader != null) { _Reader.Dispose(); _Reader = null; } if (_Provider != null) { _Provider.Dispose(); _Provider = null; } }
private void btnFile2_Click(object sender, EventArgs e) { if (ofdFile.ShowDialog(this) == DialogResult.OK) { tbFile2.Text = ofdFile.FileName; int lenExt = 4; string ext = ofdFile.FileName.Substring(ofdFile.FileName.Length - lenExt, lenExt).ToLower(); switch (ext) { case ".au": case ".snd": ar = new AuReader(File.OpenRead(ofdFile.FileName)); break; case ".wav": ar = new WaveReader(File.OpenRead(ofdFile.FileName)); break; case ".avi": ar = new AviReader(File.OpenRead(ofdFile.FileName)); if (!((AviReader)ar).HasAudio) { MessageBox.Show("Avi stream has not audio track"); return; } break; case ".mp3": ar = new Mp3Reader(File.OpenRead(ofdFile.FileName)); break; default: ar = new DsReader(ofdFile.FileName); if (!((DsReader)ar).HasAudio) { MessageBox.Show("DirectShow stream has not audio track"); return; } break; } oldFormat = ar.ReadFormat(); FormatDetails fd = AudioCompressionManager.GetFormatDetails(oldFormat); lblFileFormat.Text = string.Format("{0} {1}", AudioCompressionManager.GetFormatTagDetails(fd.FormatTag).FormatTagName, fd.FormatName); GetFormatsConverted(oldFormat); gbConvert.Enabled = true; btnMakeMp3.Enabled = false; } }
private void btnOpen_Click(object sender, EventArgs e) { if (ofdAudio.ShowDialog() == DialogResult.OK) { if (arw != null) { arw.Close(); arw = null; } string fileName = ofdAudio.FileName; arw = null; switch (Path.GetExtension(fileName.ToLower())) { case ".avi": arw = new AviReader(File.Open(fileName, FileMode.Open, FileAccess.ReadWrite)); if (!((AviReader)arw).HasAudio) { MessageBox.Show(string.Format("'{0}' file is not contains audio data", fileName)); return; } break; case ".au": case ".snd": arw = new AuReader(File.OpenRead(fileName)); break; case ".wav": arw = new WaveReadWriter(File.Open(fileName, FileMode.Open, FileAccess.ReadWrite)); break; case ".mp3": arw = new Mp3ReadWriter(File.Open(fileName, FileMode.Open, FileAccess.ReadWrite)); break; default: arw = new DsReader(fileName); if (!((DsReader)arw).HasAudio) { arw = null; MessageBox.Show(string.Format("'{0}' file is not contains audio data", fileName)); } break; } btnPlay.Enabled = arw != null; btnSave.Enabled = arw != null; } }
public IAudioReader GetAudioReader(int track) { if (track != 0 || !clip.HasAudio) { throw new Exception(string.Format("Can't read audio track {0}, because it can't be found", track)); } if (audioReader == null) { lock (this) { if (audioReader == null) { audioReader = new AvsAudioReader(clip); } } } return(audioReader); }
public void Prepare(IAudioReader wr, AudioEffect af, ref IntPtr format, ref byte[] data) { format = wr.ReadFormat(); WaveFormat wf1 = AudioCompressionManager.GetWaveFormat(format); Console.WriteLine("{0},{1},{2}-{3}", wf1.nChannels, wf1.wBitsPerSample, wf1.nSamplesPerSec, wf1.wFormatTag); data = wr.ReadData(); if (wf1.wFormatTag != 1) { IntPtr formatNew = IntPtr.Zero; byte[] dataNew = null; AudioCompressionManager.ToPcm(format, data, ref formatNew, ref dataNew); format = formatNew; data = dataNew; WaveFormat wf2 = AudioCompressionManager.GetWaveFormat(format); Console.WriteLine("{0},{1},{2}-{3}", wf2.nChannels, wf2.wBitsPerSample, wf2.nSamplesPerSec, wf2.wFormatTag); } else if (wf1.wBitsPerSample != 16) { WaveFormat wf = AudioCompressionManager.GetWaveFormat(format); IntPtr formatNew = AudioCompressionManager.GetPcmFormat(wf.nChannels, 16, wf.nSamplesPerSec); byte[] dataNew = AudioCompressionManager.Convert(format, formatNew, data, false); format = formatNew; data = dataNew; WaveFormat wf2 = AudioCompressionManager.GetWaveFormat(format); Console.WriteLine("{0},{1},{2}-{3}", wf2.nChannels, wf2.wBitsPerSample, wf2.nSamplesPerSec, wf2.wFormatTag); } //wr.Close(); if (af != null) { bool hasProcessInPlace = af.HasProcessInPlace; //af.GetSupportedOutputFormats(); GCHandle src = GCHandle.Alloc(data, GCHandleType.Pinned); IntPtr formatPtr = src.AddrOfPinnedObject(); bool res = af.ProcessInPlace(format, data); src.Free(); if (!res) { MessageBox.Show("Unable to convert the audio data"); return; } } }
private void StartAudio() { if (processor != null) { processor.Cleanup(); } processor = new FFTProcessorViewModel(FFTOptions); OnPropertyChanged(nameof(FFTViewModel)); if (reader == null) { reader = new AudioReaderViewModel(); } reader.Setup(GetReaderModel()); (reader as AudioReaderViewModel).WaveIn.BufferMilliseconds = 250; (reader as AudioReaderViewModel).WaveIn.DataAvailable += WaveIn_DataAvailable; reader.Start(); }
public IAudioReader GetAudioReader(int track) { if (track != 0 || !info.HasAudio) throw new Exception(string.Format("Can't read audio track {0}, because it can't be found", track)); if (audioReader == null) lock (this) { if (audioReader == null) audioReader = new AvsAudioReader(clip); } return audioReader; }
public static void BuildParseCompareAudio(IAudioFormat audio, IAudioWriter writer, IAudioReader reader) { byte[] builtFile = writer.GetFile(audio); IAudioFormat parsedAudio = reader.ReadFormat(builtFile); Assert.Equal(audio, parsedAudio, new AudioFormatComparer()); }
public SampleReader(IAudioReader reader, bool loop) { _reader = reader; WaveFormat = reader.WaveFormat; _loop = loop; }
/// <summary> /// Gets the appropriate metadata reader for a given file / physical data reader /// </summary> /// <param name="path">Path of the file</param> /// <param name="theDataReader">AudioDataReader produced for this file</param> /// <returns>Metadata reader able to give metadata info for this file (or the dummy reader if the format is unknown)</returns> public IMetadataReader GetMetaReader(String path, IAudioReader theDataReader) { IMetadataReader theMetaReader = null; // Step 1 : The physical reader may have already parsed the metadata for (int i=0; i<TAG_TYPE_COUNT; i++) { if ( (TAG_ID3V1 == tagPriority[i]) && (theDataReader.ID3v1.Exists) ) { theMetaReader = theDataReader.ID3v1; break; } if ( (TAG_ID3V2 == tagPriority[i]) && (theDataReader.ID3v2.Exists) ) { theMetaReader = theDataReader.ID3v2; break; } if ( (TAG_APE == tagPriority[i]) && (theDataReader.APEtag.Exists) ) { theMetaReader = theDataReader.APEtag; break; } } // Step 2 : Nothing found in step 1 -> considerate specific tagging (data+meta file formats) if (null == theMetaReader) { //# improve something here /* if (theDataReader is BinaryLogic.TOggVorbis) { BinaryLogic.TOggVorbis theVorbis = new BinaryLogic.TOggVorbis(); theVorbis.ReadFromFile(path); theMetaReader = theVorbis; } if (theDataReader is BinaryLogic.TWMAfile) { BinaryLogic.TWMAfile theWMA = new BinaryLogic.TWMAfile(); theWMA.ReadFromFile(path); theMetaReader = theWMA; } if (theDataReader is BinaryLogic.TFLACFile) { BinaryLogic.TFLACFile theFLAC = new BinaryLogic.TFLACFile(); theFLAC.ReadFromFile(path); theMetaReader = theFLAC; } if (theDataReader is BinaryLogic.TPSFFile) { BinaryLogic.TPSFFile thePSF = new BinaryLogic.TPSFFile(); thePSF.ReadFromFile(path); theMetaReader = thePSF; } if (theDataReader is BinaryLogic.TSPCFile) { BinaryLogic.TSPCFile theSPC = new BinaryLogic.TSPCFile(); theSPC.ReadFromFile(path); theMetaReader = theSPC; }*/ if ((theDataReader is BinaryLogic.TOggVorbis) || (theDataReader is BinaryLogic.TWMAfile) || (theDataReader is BinaryLogic.TFLACFile) || (theDataReader is BinaryLogic.TPSFFile) || (theDataReader is BinaryLogic.TSPCFile) ) { theMetaReader = (IMetadataReader)theDataReader; // Boorish but correct cast } } // Step 3 : default (no tagging at all - provides the dummy reader) if (null == theMetaReader) theMetaReader = new BinaryLogic.DummyTag(); return theMetaReader; }
private void btnOpen_Click(object sender, EventArgs e) { if (ofdAudio.ShowDialog() == DialogResult.OK) { if (arw != null) { arw.Close(); arw = null; } string fileName = ofdAudio.FileName; arw = null; switch (Path.GetExtension(fileName.ToLower())) { case ".avi": arw = new AviReader(File.Open(fileName, FileMode.Open, FileAccess.ReadWrite)); if (!((AviReader)arw).HasAudio) { MessageBox.Show(string.Format("'{0}' file is not contains audio data", fileName)); return; } break; case ".au": case ".snd": arw = new AuReader(File.OpenRead(fileName)); break; case ".wav": arw = new WaveReadWriter(File.Open(fileName, FileMode.Open, FileAccess.ReadWrite)); break; case ".mp3": arw = new Mp3ReadWriter(File.Open(fileName, FileMode.Open, FileAccess.ReadWrite)); break; default: arw = new DsReader(fileName); if (!((DsReader)arw).HasAudio) { arw = null; MessageBox.Show(string.Format("'{0}' file is not contains audio data", fileName)); } break; } btnPlay.Enabled = arw != null; } }
/// <summary> /// Gets the appropriate metadata reader for a given file / physical data reader /// </summary> /// <param name="path">Path of the file</param> /// <param name="theDataReader">AudioDataReader produced for this file</param> /// <returns>Metadata reader able to give metadata info for this file (or the dummy reader if the format is unknown)</returns> public IMetadataReader GetMetaReader(String path, IAudioReader theDataReader) { IMetadataReader theMetaReader = null; // Step 1 : The physical reader may have already parsed the metadata for (int i = 0; i < TAG_TYPE_COUNT; i++) { if ((TAG_ID3V1 == tagPriority[i]) && (theDataReader.ID3v1.Exists)) { theMetaReader = theDataReader.ID3v1; break; } if ((TAG_ID3V2 == tagPriority[i]) && (theDataReader.ID3v2.Exists)) { theMetaReader = theDataReader.ID3v2; break; } if ((TAG_APE == tagPriority[i]) && (theDataReader.APEtag.Exists)) { theMetaReader = theDataReader.APEtag; break; } } // Step 2 : Nothing found in step 1 -> considerate specific tagging (data+meta file formats) if (null == theMetaReader) { //# improve something here /* * if (theDataReader is BinaryLogic.TOggVorbis) * { * BinaryLogic.TOggVorbis theVorbis = new BinaryLogic.TOggVorbis(); * theVorbis.ReadFromFile(path); * theMetaReader = theVorbis; * } * * if (theDataReader is BinaryLogic.TWMAfile) * { * BinaryLogic.TWMAfile theWMA = new BinaryLogic.TWMAfile(); * theWMA.ReadFromFile(path); * theMetaReader = theWMA; * } * * if (theDataReader is BinaryLogic.TFLACFile) * { * BinaryLogic.TFLACFile theFLAC = new BinaryLogic.TFLACFile(); * theFLAC.ReadFromFile(path); * theMetaReader = theFLAC; * } * * if (theDataReader is BinaryLogic.TPSFFile) * { * BinaryLogic.TPSFFile thePSF = new BinaryLogic.TPSFFile(); * thePSF.ReadFromFile(path); * theMetaReader = thePSF; * } * * if (theDataReader is BinaryLogic.TSPCFile) * { * BinaryLogic.TSPCFile theSPC = new BinaryLogic.TSPCFile(); * theSPC.ReadFromFile(path); * theMetaReader = theSPC; * }*/ if ((theDataReader is BinaryLogic.TOggVorbis) || (theDataReader is BinaryLogic.TWMAfile) || (theDataReader is BinaryLogic.TFLACFile) || (theDataReader is BinaryLogic.TPSFFile) || (theDataReader is BinaryLogic.TSPCFile)) { theMetaReader = (IMetadataReader)theDataReader; // Boorish but correct cast } } // Step 3 : default (no tagging at all - provides the dummy reader) if (null == theMetaReader) { theMetaReader = new BinaryLogic.DummyTag(); } return(theMetaReader); }
/// <summary> /// Gets the appropriate physical data reader for a given file and format codec /// </summary> /// <param name="path">The path of the file</param> /// <param name="code">The codec of the file</param> /// <returns>AudioDataReader able to give info about the file's contents (or the dummy reader if the format is unknown)</returns> public IAudioReader GetDataReader(String path, Codec codec) { IAudioReader theDataReader = null; switch (codec) { case Codec.MP3: theDataReader = new BinaryLogic.TMPEGaudio(); break; case Codec.OGG: theDataReader = new BinaryLogic.TOggVorbis(); break; case Codec.MPC: theDataReader = new BinaryLogic.TMPEGplus(); break; case Codec.FLAC: theDataReader = new BinaryLogic.TFLACFile(); break; case Codec.APE: theDataReader = new BinaryLogic.TMonkey(); break; case Codec.WMA: theDataReader = new BinaryLogic.TWMAfile(); break; case Codec.MIDI: theDataReader = new BinaryLogic.Midi(); break; case Codec.AAC: theDataReader = new BinaryLogic.TAACfile(); break; case Codec.AC3: theDataReader = new BinaryLogic.TAC3(); break; case Codec.OFR: theDataReader = new BinaryLogic.TOptimFrog(); break; case Codec.WAVPACK: theDataReader = new BinaryLogic.TWAVPackfile(); break; case Codec.WAV: theDataReader = new BinaryLogic.TWAVfile(); break; case Codec.PSF: theDataReader = new BinaryLogic.TPSFFile(); break; case Codec.SPC: theDataReader = new BinaryLogic.TSPCFile(); break; default: theDataReader = new BinaryLogic.DummyReader(); break; } theDataReader.ReadFromFile(path); return(theDataReader); }
private void btnFile2_Click(object sender, EventArgs e) { if (ofdFile.ShowDialog(this) == DialogResult.OK) { tbFile2.Text = ofdFile.FileName; int lenExt = 4; string ext = ofdFile.FileName.Substring(ofdFile.FileName.Length - lenExt, lenExt).ToLower(); switch (ext) { case ".au": case ".snd": ar = new AuReader(File.OpenRead(ofdFile.FileName)); break; case ".wav": ar = new WaveReader(File.OpenRead(ofdFile.FileName)); break; case ".avi" : ar = new AviReader(File.OpenRead(ofdFile.FileName)); if (!((AviReader)ar).HasAudio) { MessageBox.Show("Avi stream has not audio track"); return; } break; case ".mp3" : ar = new Mp3Reader(File.OpenRead(ofdFile.FileName)); break; default: ar = new DsReader(ofdFile.FileName); if (!((DsReader)ar).HasAudio) { MessageBox.Show("DirectShow stream has not audio track"); return; } break; } oldFormat = ar.ReadFormat(); FormatDetails fd = AudioCompressionManager.GetFormatDetails(oldFormat); lblFileFormat.Text = string.Format("{0} {1}", AudioCompressionManager.GetFormatTagDetails(fd.FormatTag).FormatTagName, fd.FormatName); GetFormatsConverted(oldFormat); gbConvert.Enabled = true; btnMakeMp3.Enabled = false; } }
private string[] IntspectFile(string fileName) { ID3v1 m_id3; Dictionary <WaveInfo, string> m_waveTags = null; IAudioReader ar = null; Stream stream = null; string ext = Path.GetExtension(fileName.ToLower()); m_id3 = null; m_waveTags = null; switch (ext) { case ".avi": stream = File.OpenRead(fileName); ar = new AviReader(stream); if (!((AviReader)ar).HasAudio) { return(new string[] { string.Format("'{0}' file is not contains audio data", fileName) }); } break; case ".au": case ".snd": ar = new AuReader(File.OpenRead(fileName)); break; case ".wav": stream = File.OpenRead(fileName); ar = new WaveReader(stream); m_waveTags = (ar as WaveReader).ReadInfoTag(); break; case ".mp3": stream = File.OpenRead(fileName); ar = new Mp3Reader(stream); Mp3Reader mrID3 = new Mp3Reader(File.OpenRead(fileName)); m_id3 = mrID3.ReadID3v1Tag(); break; default: ar = new DsReader(fileName); if (!((DsReader)ar).HasAudio) { return(new string[] { string.Format("'{0}' file is not contains audio data", fileName) }); } break; } IntPtr format = ar.ReadFormat(); WaveFormat wf = AudioCompressionManager.GetWaveFormat(format); List <string> list = new List <string>(); list.Add(string.Format("Opening {0}", fileName)); list.Add(string.Format("{0}, {1} Hz, {2} channels, {3} bits per sample", GetFormatTagName(wf.wFormatTag), wf.nSamplesPerSec, wf.nChannels, wf.wBitsPerSample)); list.Add(string.Format("Block Align: {0}, Average Bytes Per Second: {1}", wf.nBlockAlign, wf.nAvgBytesPerSec)); TimeSpan duration = TimeSpan.FromMilliseconds(ar.GetDurationInMS()); list.Add(string.Format("Duration: {0}", duration)); if (m_id3 != null) { list.Add("--------- ID3 -----------"); list.Add(string.Format("Title: {0}", m_id3.Title)); list.Add(string.Format("Artist: {0}", m_id3.Artist)); list.Add(string.Format("Album: {0}", m_id3.Album)); list.Add(string.Format("Year: {0}", m_id3.Year)); list.Add(string.Format("Genre: {0}", m_id3.Genre.ToString())); list.Add(string.Format("Comment: {0}", m_id3.Comment)); } if (m_waveTags != null) { list.Add("--------- Wave tags -----------"); foreach (WaveInfo key in m_waveTags.Keys) { list.Add(string.Format("{0}: {1}", key.ToString(), m_waveTags[key])); } } ar.Close(); return(list.ToArray()); }