Example #1
0
			public static void AddMarkers(String WaveFile, Dictionary<double, string> Markers)
			{
				var file = new RiffFile(WaveFile, false);

				var reader = new WaveFileReader(WaveFile);
				WaveFormat fmt = reader.WaveFormat;

				string temp1name = Path.GetDirectoryName(WaveFile) + Path.GetFileNameWithoutExtension(WaveFile) + "-temp" +
								   Path.GetExtension(WaveFile);

				// find old cue chunk, or add new
				var cueChunk = file.GetChunk<CkCue>() as CkCue;
				if (cueChunk == null)
				{
					cueChunk = file.AddChunk(CkType.cue) as CkCue;
				}
				else
					cueChunk.CuePoints.Clear();

				var listChunk = file.GetChunk<CkList>() as CkList;
				if (listChunk == null || listChunk.TypeID != LiCkType.adtl)
				{
					listChunk = file.AddChunk(CkType.LIST) as CkList;
					if (listChunk != null) listChunk.TypeID = LiCkType.adtl;
				}

				if (listChunk != null) listChunk.Chunks.Clear();

				uint cueCounter = 0;

				foreach (var pair in Markers)
				{
					var samplePos = (uint)(pair.Key * fmt.SampleRate);
					var cp = new CuePoint(samplePos) { ID = ++cueCounter };
					if (cueChunk != null) cueChunk.CuePoints.Add(cp);
					var labl = new LiCkInfoLabl(cp, pair.Value);
					if (listChunk != null) listChunk.Chunks.Add(labl);
				}
				reader.Close();
				reader.Dispose();
				file.Save(temp1name);
				file.Close();

				File.Replace(temp1name, WaveFile, null);
			}
Example #2
0
		/// <summary>
		/// Checks if the cue and list chunks exist and if so, creates a cue list
		/// </summary>
		internal static CueList FromChunks(WaveFileReader reader)
		{
			CueList cueList = null;
			byte[] cueChunkData = null;
			byte[] listChunkData = null;

			foreach (RiffChunk chunk in reader.ExtraChunks)
			{
				if (chunk.IdentifierAsString.ToLower() == "cue ")
				{
					cueChunkData = reader.GetChunkData(chunk);
				}
				else if (chunk.IdentifierAsString.ToLower() == "list")
				{
					listChunkData = reader.GetChunkData(chunk);
				}
			}
			if (cueChunkData != null && listChunkData != null)
			{
				cueList = new CueList(cueChunkData, listChunkData);
			}
			return cueList;
		}
Example #3
0
			public static void StripPadding(string WaveFile, int Seconds)
			{
				var reader = new WaveFileReader(WaveFile);
				var strTarget = new BinaryWriter(new MemoryStream());
				WaveFormat fmt = reader.WaveFormat;

				string temp1name = Path.GetDirectoryName(WaveFile) + Path.DirectorySeparatorChar +
								   Path.GetFileNameWithoutExtension(WaveFile) + "-temp." + Path.GetExtension(WaveFile);
				string temp2name = Path.GetDirectoryName(WaveFile) + Path.DirectorySeparatorChar +
								   Path.GetFileNameWithoutExtension(WaveFile) + "-old." + Path.GetExtension(WaveFile);
				int samples = fmt.SampleRate * Seconds;
				int sampleSize = (fmt.BitsPerSample / 8) * fmt.Channels;
				int padBytes = samples * sampleSize;
				var bufsize = (int)(reader.Length - (padBytes * 2));
				var buf = new byte[bufsize];
				int newSampleCount = bufsize / sampleSize;

				reader.Seek(padBytes, SeekOrigin.Begin);
				strTarget.Write(reader.Read(buf, 0, buf.Length));
				reader.Close();
				reader.Dispose();

				var file = new RiffFile(WaveFile, false);
				file.GetChunk<CkData>().Data = buf;

				// adjust marker positions, remove if outside
				foreach (Chunk ch in file.Chunks)
				{
					if (ch.GetType() == typeof(CkCue))
					{
						var me = ch as CkCue;
						//foreach (CuePoint cp in me.CuePoints)
						if (me != null)
							for (int i = me.CuePoints.Count - 1; i >= 0; i--)
							{
								CuePoint cp = me.CuePoints[i];
								cp.Position -= (uint)samples;
								cp.SampleOffset -= (uint)samples;
								if (cp.Position > newSampleCount)
									me.CuePoints.Remove(cp);
							}
					}

						// trim down region lengths (ugly, but necessary due to Vegas rounding rather than truncating)
					else if (ch is CkList)
					{
						var me = ch as CkList;
						foreach (ListChunk lch in me.Chunks)
						{
							if (lch.GetType() == typeof(LiCkLtxt))
							{
								var lt = lch as LiCkLtxt;
								if (lt != null && lt.SampleLength > newSampleCount)
								{
									lt.SampleLength = (uint)newSampleCount;
								}
							}
							else if (lch.GetType() == typeof(LiCkInfoTCOD))
							{
								var tch = lch as LiCkInfoTCOD;
								if (tch != null) tch.Position += (uint)samples;
							}
							else if (lch.GetType() == typeof(LiCkInfoTCDO))
							{
								var tch = lch as LiCkInfoTCDO;
								if (tch != null) tch.Position -= (uint)samples;
							}
						}
					}
				}
				file.Save(temp1name);
				File.Move(WaveFile, temp2name);
				File.Move(temp1name, WaveFile);
				File.Delete(temp2name);
			}
Example #4
0
		/// <summary>
		/// Function to encode a Wave file to OGG
		/// </summary>
		/// <param name="infile">Wave file name</param>
		/// <param name="outfile">Ogg file name</param>
		public void Encode(string infile, string outfile)
		{
			var reader = new WaveFileReader(infile);
			Stream stdout = File.OpenWrite(outfile);


			try
			{
				// Encode setup
				OggInterop.vorbis_info_init(vi);

				// choose an encoding mode

				/*********************************************************************
				Encoding using a VBR quality mode.  The usable range is -.1
				(lowest quality, smallest file) to 1. (highest quality, largest file).
				Example quality mode .4: 44kHz stereo coupled, roughly 128kbps VBR 

				ret = vorbis_encode_init_vbr(&vi,2,44100,.4);

				---------------------------------------------------------------------

				Encoding using an average bitrate mode (ABR).
				example: 44kHz stereo coupled, average 128kbps VBR 

				ret = vorbis_encode_init(&vi,2,44100,-1,128000,-1);

				---------------------------------------------------------------------

				Encode using a qulity mode, but select that quality mode by asking for
				an approximate bitrate.  This is not ABR, it is true VBR, but selected
				using the bitrate interface, and then turning bitrate management off:

				ret = ( vorbis_encode_setup_managed(&vi,2,44100,-1,128000,-1) ||
					vorbis_encode_ctl(&vi,OV_ECTL_RATEMANAGE_AVG,NULL) ||
					vorbis_encode_setup_init(&vi));

				*********************************************************************/

				// do not continue if setup failed; this can happen if we ask for a
				// mode that libVorbis does not support (eg, too low a bitrate, etc,
				// will return 'OV_EIMPL')
				if (OggInterop.vorbis_encode_init_vbr(vi, reader.WaveFormat.Channels, reader.WaveFormat.SampleRate, 0.5f) != 0)
					throw new ApplicationException("vorbis_encode_init_vbr");

				// add a comment
				//vorbis_comment_init(vc);
				//vorbis_comment_add_tag(vc,"ENCODER","OggEncoder.cs");
				//vorbis_comment_add_tag(vc,"ARTIST","Mark Heath");
				//vorbis_comment_add_tag(vc,"TITLE",Path.GetFileNameWithoutExtension(infile));

				// MRH: possibly redundant step, but in the oggtools app
				// seems to let us get past the null reference exception in
				// vorbis_analysis_init the second time through
				// (but then we get stuck on vorbis_info_clear)
				OggInterop.vorbis_encode_setup_init(vi);

				// set up the analysis state and auxiliary encoding storage
				if (OggInterop.vorbis_analysis_init(vd, vi) != 0)
					throw new ApplicationException("vorbis_analysis_init error");

				if (OggInterop.vorbis_block_init(vd, vb) != 0)
					throw new ApplicationException("vorbis_block_init error");

				// set up our packet->stream encoder
				// pick a random serial number; that way we can more likely build
				// chained streams just by concatenation
				var rand = new Random();
				if (OggInterop.ogg_stream_init(os, rand.Next()) != 0)
					throw new ApplicationException("ogg_stream_init error");

				// Vorbis streams begin with three headers; the initial header (with
				// most of the codec setup parameters) which is mandated by the Ogg
				// bitstream spec.  The second header holds any comment fields.  The
				// third header holds the bitstream codebook.  We merely need to
				// make the headers, then pass them to libvorbis one at a time;
				// libvorbis handles the additional Ogg bitstream constraints 

				IntPtr header = AllocateHGlobal(64); //ogg_packet 
				IntPtr header_comments = AllocateHGlobal(64); //ogg_packet 
				IntPtr header_codebook = AllocateHGlobal(64); //ogg_packet 

				OggInterop.vorbis_analysis_headerout(vd, vc, header, header_comments, header_codebook);
				OggInterop.ogg_stream_packetin(os, header); // automatically placed in its own page
				OggInterop.ogg_stream_packetin(os, header_comments);
				OggInterop.ogg_stream_packetin(os, header_codebook);

				// This ensures the actual audio data will start on a new page, as per spec
				while (OggInterop.ogg_stream_flush(os, og) != 0)
				{
					WriteOg(og, stdout);
				}

				var samplebuffer = new float[reader.WaveFormat.Channels][];
				for (int channel = 0; channel < reader.WaveFormat.Channels; channel++)
				{
					samplebuffer[channel] = new float[READ];
				}

				bool eos = false;
				while (!eos)
				{
					int samples = reader.Read(samplebuffer, READ);
					if (samples == 0)
					{
						// end of file.  this can be done implicitly in the mainline,
						//but it's easier to see here in non-clever fashion.
						//Tell the library we're at end of stream so that it can handle
						//the last frame and mark end of stream in the output properly 
						OggInterop.vorbis_analysis_wrote(vd, 0);
					}
					else
					{
						// data to encode 
						// expose the buffer to submit data 
						IntPtr bufferpointer = OggInterop.vorbis_analysis_buffer(vd, samples);
						var floatpointers = new int[reader.WaveFormat.Channels];
						Marshal.Copy(bufferpointer, floatpointers, 0, reader.WaveFormat.Channels);
						for (int channel = 0; channel < reader.WaveFormat.Channels; channel++)
						{
							var channelbuffer = new IntPtr(floatpointers[channel]);
							Marshal.Copy(samplebuffer[channel], 0, channelbuffer, samples);
						}

						// tell the library how much we actually submitted
						OggInterop.vorbis_analysis_wrote(vd, samples);
					}

					// vorbis does some data preanalysis, then divvies up blocks for
					// more involved (potentially parallel) processing.  Get a single
					// block for encoding now
					while (OggInterop.vorbis_analysis_blockout(vd, vb) == 1)
					{
						/* analysis, assume we want to use bitrate management */
						OggInterop.vorbis_analysis(vb, IntPtr.Zero);
						OggInterop.vorbis_bitrate_addblock(vb);

						while (OggInterop.vorbis_bitrate_flushpacket(vd, op) != 0)
						{
							/* weld the packet into the bitstream */
							OggInterop.ogg_stream_packetin(os, op);

							/* write out pages (if any) */
							while (!eos)
							{
								int result = OggInterop.ogg_stream_pageout(os, og);
								if (result == 0)
									break;
								WriteOg(og, stdout);

								/* this could be set above, but for illustrative purposes, I do
								it here (to show that vorbis does know where the stream ends) */

								if (OggInterop.ogg_page_eos(og) != 0)
									eos = true;
							}
						}
					}
				}

				// clean up and exit.  vorbis_info_clear() must be called last */

				if (OggInterop.ogg_stream_clear(os) != 0)
					throw new ApplicationException("ogg_stream_clear error");
				if (OggInterop.vorbis_block_clear(vb) != 0)
					throw new ApplicationException("vorbis_block_clear error");
				OggInterop.vorbis_dsp_clear(vd);
				//vorbis_comment_clear(vc);			
				OggInterop.vorbis_info_clear(vi);


				// ogg_page and ogg_packet structs always point to storage in
				// libvorbis.  They're never freed or manipulated directly
			}
			finally
			{
				reader.Dispose();
				stdout.Close();
			}
			GC.KeepAlive(this);
		}