/* replacereaderclr: test program for mpg123clr, showing how to use ReplaceReader in a CLR enviro. copyright 2009 by the mpg123 project - free software under the terms of the LGPL 2.1 see COPYING and AUTHORS files in distribution or http://mpg123.org initially written by Malcolm Boczek not to be used as an example of good coding practices, note the total absence of error handling!!! */ /* 1.9.0.0 24-Sep-09 Function names harmonized with libmpg123 (mb) 1.12.0.0 14-Apr-10 Added ReplaceReaderHandle sample code (mb) */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; // for ReplaceReaderHandle example using System.Runtime.InteropServices; // for ReplaceReaderHandle example using mpg123clr; namespace ReplaceReaderclr { class Program { private unsafe static int MyReadFunc(int a, void* b, uint c) { // need to call posix read function here... // PosixRead is an example, substitute your replacement function here. int ret = mpg123.PosixRead(a, b, c); return ret; } private static int MySeekFunc(int a, int b, int c) { // NOTE: Largefile conflict with use of "int" position values. // Convert to long if off_t is defined as long long // need to call posix lseek function here... // PosixSeek is an example, substitute your replacement function here. int ret = mpg123.PosixSeek(a, b, c); return ret; } private unsafe static int MyHandleReadFunc(void* a, void* b, uint c) { GCHandle gch = GCHandle.FromIntPtr((IntPtr)a); BinaryReader br = (BinaryReader)gch.Target; byte[] buf = br.ReadBytes((int)c); // NOTE: no discernible performance difference between Marshal.Copy and ptr++ loop Marshal.Copy(buf, 0, (IntPtr)b, buf.Length); // byte* ptr = (byte*)b; // for (int i = 0, l = buf.Length; i < l; i++) // *(ptr++) = buf[i]; return buf.Length; } private unsafe static int MyHandleSeekFunc(void* a, int b, int c) { // NOTE: Largefile conflict with use of "int" position values. // Convert to long if off_t is defined as long long GCHandle gch = GCHandle.FromIntPtr((IntPtr)a); BinaryReader br = (BinaryReader)gch.Target; return (int)br.BaseStream.Seek(b, (SeekOrigin)c); } private unsafe static void MyHandleCleanFunc(void* a) { GCHandle gch = GCHandle.FromIntPtr((IntPtr)a); BinaryReader br = (BinaryReader)gch.Target; br.Close(); } static unsafe void Main(string[] args) { if (args.Length == 0) { Console.WriteLine("I need a file to work on:\n\nPress any key to exit."); while (Console.Read() == 0) ; return; } mpg123clr.mpg.ErrorCode err; string filename = args[0]; err = mpg123.mpg123_init(); Console.WriteLine("Init:"); RunReplaceReaderTest(filename); RunReplaceReaderHandleTest(filename); RunFrameByFrameTest(filename); Console.WriteLine("\nPress any key to exit:"); while (Console.Read() == 0) ; mpg123.mpg123_exit(); } static unsafe void RunReplaceReaderTest(string filename) { mpg123clr.mpg.ErrorCode err; mpg123 mp = new mpg123(); err = mp.mpg123_new(); // ReplaceReader example mpg123clr.mpg123.ReadDelegate rdel = MyReadFunc; mpg123clr.mpg123.SeekDelegate sdel = MySeekFunc; err = mp.mpg123_replace_reader(rdel, sdel); //err = mp.mpg123_open(args[0]); err = mp.mpg123_open(filename); if (err != mpg123clr.mpg.ErrorCode.ok) { Console.WriteLine("Error: " + mp.mpg123_strerror()); } else { Console.WriteLine("Open:"); // Show available decoders string[] Decoders = mp.mpg123_decoders(); if (Decoders.Length > 0) { Console.WriteLine("\nDecoders:"); foreach (string str in Decoders) Console.WriteLine(str); } // Show supported decoders string[] supDecoders = mp.mpg123_supported_decoders(); if (supDecoders.Length > 0) { Console.WriteLine("\nSupported Decoders:"); foreach (string str in supDecoders) Console.WriteLine(str); } // Show actual decoder Console.WriteLine("\nDecoder: " + mp.mpg123_current_decoder()); // Show estimated file length Console.WriteLine("\nLength Estimate: " + mp.mpg123_length().ToString()); // Scan - gets actual details including ID3v2 and Frame offsets err = mp.mpg123_scan(); // Show actual file length if (err == mpg123clr.mpg.ErrorCode.ok) Console.WriteLine("Length Actual : " + mp.mpg123_length().ToString()); // Get ID3 data mpg123clr.id3.mpg123id3v1 iv1; mpg123clr.id3.mpg123id3v2 iv2; err = mp.mpg123_id3(out iv1, out iv2); // Show ID3v2 data Console.WriteLine("\nTitle : " + iv2.title); Console.WriteLine("Artist : " + iv2.artist); Console.WriteLine("Album : " + iv2.album); Console.WriteLine("Comment: " + iv2.comment); Console.WriteLine("Year : " + iv2.year); // Demo seek (back to start of file - note: scan should already have done this) long pos = mp.mpg123_seek(0, System.IO.SeekOrigin.Begin); long[] frameindex; long step; err = mp.mpg123_index(out frameindex, out step); if (err == mpg123clr.mpg.ErrorCode.ok) { Console.WriteLine("\nFrameIndex:"); foreach (long idx in frameindex) { // Console.WriteLine(idx.ToString()); } } int num; uint cnt; IntPtr audio; // Walk the file - effectively decode the data without using it... Console.WriteLine("\nWalking : " + iv2.title); DateTime dte, dts = DateTime.Now; while (err == mpg123clr.mpg.ErrorCode.ok || err == mpg123clr.mpg.ErrorCode.new_format) { err = mp.mpg123_decode_frame(out num, out audio, out cnt); // do something with "audio" here.... } dte = DateTime.Now; TimeSpan ts = dte - dts; Console.WriteLine("Duration: " + ts.ToString()); mp.mpg123_close(); } mp.Dispose(); } static unsafe void RunReplaceReaderHandleTest(string filename) { mpg123clr.mpg.ErrorCode err; mpg123 mp = new mpg123(); err = mp.mpg123_new(); // ReplaceReader example mpg123clr.mpg123.ReadHandleDelegate rdel = MyHandleReadFunc; mpg123clr.mpg123.SeekHandleDelegate sdel = MyHandleSeekFunc; mpg123clr.mpg123.CleanupHandleDelegate cdel = MyHandleCleanFunc; err = mp.mpg123_replace_reader_handle(rdel, sdel, cdel); //err = mp.mpg123_open(args[0]); BinaryReader br = new BinaryReader(File.OpenRead(filename)); err = mp.mpg123_open_handle(br); if (err != mpg123clr.mpg.ErrorCode.ok) { Console.WriteLine("Error: " + mp.mpg123_strerror()); } else { Console.WriteLine("Open:"); // Show available decoders string[] Decoders = mp.mpg123_decoders(); if (Decoders.Length > 0) { Console.WriteLine("\nDecoders:"); foreach (string str in Decoders) Console.WriteLine(str); } // Show supported decoders string[] supDecoders = mp.mpg123_supported_decoders(); if (supDecoders.Length > 0) { Console.WriteLine("\nSupported Decoders:"); foreach (string str in supDecoders) Console.WriteLine(str); } // Show actual decoder Console.WriteLine("\nDecoder: " + mp.mpg123_current_decoder()); // Show estimated file length Console.WriteLine("\nLength Estimate: " + mp.mpg123_length().ToString()); // Scan - gets actual details including ID3v2 and Frame offsets err = mp.mpg123_scan(); // Show actual file length if (err == mpg123clr.mpg.ErrorCode.ok) Console.WriteLine("Length Actual : " + mp.mpg123_length().ToString()); // Get ID3 data mpg123clr.id3.mpg123id3v1 iv1; mpg123clr.id3.mpg123id3v2 iv2; err = mp.mpg123_id3(out iv1, out iv2); // Show ID3v2 data Console.WriteLine("\nTitle : " + iv2.title); Console.WriteLine("Artist : " + iv2.artist); Console.WriteLine("Album : " + iv2.album); Console.WriteLine("Comment: " + iv2.comment); Console.WriteLine("Year : " + iv2.year); // Demo seek (back to start of file - note: scan should already have done this) long pos = mp.mpg123_seek(0, System.IO.SeekOrigin.Begin); long[] frameindex; long step; err = mp.mpg123_index(out frameindex, out step); if (err == mpg123clr.mpg.ErrorCode.ok) { Console.WriteLine("\nFrameIndex:"); foreach (long idx in frameindex) { // Console.WriteLine(idx.ToString()); } } int num; uint cnt; IntPtr audio; // Walk the file - effectively decode the data without using it... Console.WriteLine("\nWalking : " + iv2.title); DateTime dte, dts = DateTime.Now; while (err == mpg123clr.mpg.ErrorCode.ok || err == mpg123clr.mpg.ErrorCode.new_format) { err = mp.mpg123_decode_frame(out num, out audio, out cnt); // do something with "audio" here.... } dte = DateTime.Now; TimeSpan ts = dte - dts; Console.WriteLine("Duration: " + ts.ToString()); mp.mpg123_close(); } mp.Dispose(); } static unsafe void RunFrameByFrameTest(string filename) { mpg123clr.mpg.ErrorCode err; mpg123 mp = new mpg123(); err = mp.mpg123_new(); err = mp.mpg123_open(filename); if (err != mpg123clr.mpg.ErrorCode.ok) { Console.WriteLine("Error: " + mp.mpg123_strerror()); } else { Console.WriteLine("Open:"); // Show available decoders string[] Decoders = mp.mpg123_decoders(); if (Decoders.Length > 0) { Console.WriteLine("\nDecoders:"); foreach (string str in Decoders) Console.WriteLine(str); } // Show supported decoders string[] supDecoders = mp.mpg123_supported_decoders(); if (supDecoders.Length > 0) { Console.WriteLine("\nSupported Decoders:"); foreach (string str in supDecoders) Console.WriteLine(str); } // Show actual decoder Console.WriteLine("\nDecoder: " + mp.mpg123_current_decoder()); // Show estimated file length Console.WriteLine("\nLength Estimate: " + mp.mpg123_length().ToString()); // Scan - gets actual details including ID3v2 and Frame offsets err = mp.mpg123_scan(); // Show actual file length if (err == mpg123clr.mpg.ErrorCode.ok) Console.WriteLine("Length Actual : " + mp.mpg123_length().ToString()); // Get ID3 data mpg123clr.id3.mpg123id3v1 iv1; mpg123clr.id3.mpg123id3v2 iv2; err = mp.mpg123_id3(out iv1, out iv2); // Show ID3v2 data Console.WriteLine("\nTitle : " + iv2.title); Console.WriteLine("Artist : " + iv2.artist); Console.WriteLine("Album : " + iv2.album); Console.WriteLine("Comment: " + iv2.comment); Console.WriteLine("Year : " + iv2.year); // Demo seek (back to start of file - note: scan should already have done this) long pos = mp.mpg123_seek(0, System.IO.SeekOrigin.Begin); long[] frameindex; long step; err = mp.mpg123_index(out frameindex, out step); if (err == mpg123clr.mpg.ErrorCode.ok) { Console.WriteLine("\nFrameIndex:"); foreach (long idx in frameindex) { // Console.WriteLine(idx.ToString()); } } int num; uint cnt; IntPtr audio; // Walk the file - effectively decode the data without using it... Console.WriteLine("\nFrame Walking : " + iv2.title); DateTime dte, dts = DateTime.Now; while (err == mpg123clr.mpg.ErrorCode.ok || err == mpg123clr.mpg.ErrorCode.new_format) { err = mp.mpg123_framebyframe_decode(out num, out audio, out cnt); err = mp.mpg123_framebyframe_next(); // do something with "audio" here.... } dte = DateTime.Now; TimeSpan ts = dte - dts; Console.WriteLine("Duration: " + ts.ToString()); mp.mpg123_close(); } mp.Dispose(); } } }