|
Packit |
c32a2d |
/*
|
|
Packit |
c32a2d |
feedseekclr: test program for mpg123clr, showing how to use fuzzy seeking in feeder mode
|
|
Packit |
c32a2d |
copyright 2009 by the mpg123 project - free software under the terms of the LGPL 2.1
|
|
Packit |
c32a2d |
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
based on feedseek.c example for libmpg123.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
Comment (Malcolm Boczek)
|
|
Packit |
c32a2d |
this CLR example has been written to allow easy comparison to the original feedseek.c example
|
|
Packit |
c32a2d |
and uses some constructs that would not normally be used in a C# environment,
|
|
Packit |
c32a2d |
eg: byte[]/ASCII text, Marshal.Copy, static fields, lots of casts etc.
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/*
|
|
Packit |
c32a2d |
1.9.0.0 24-Sep-09 Function names harmonized with libmpg123 (mb)
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
using System;
|
|
Packit |
c32a2d |
using System.Collections.Generic;
|
|
Packit |
c32a2d |
using System.Linq;
|
|
Packit |
c32a2d |
using System.Text;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
using System.IO;
|
|
Packit |
c32a2d |
using System.Runtime.InteropServices;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
using mpg123clr;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
namespace feedseekclr
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
class Program
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
const int WAVE_FORMAT_PCM = 0x0001;
|
|
Packit |
c32a2d |
const int WAVE_FORMAT_IEEE_FLOAT = 0x0003;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static BinaryWriter _out;
|
|
Packit |
c32a2d |
static long totaloffset, dataoffset;
|
|
Packit |
c32a2d |
static int rate;
|
|
Packit |
c32a2d |
static mpg123clr.mpg.channelcount channels;
|
|
Packit |
c32a2d |
static mpg123clr.mpg.enc enc;
|
|
Packit |
c32a2d |
static short bitspersample, wavformat;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
// write wav header
|
|
Packit |
c32a2d |
static void initwav()
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
uint tmp32 = 0;
|
|
Packit |
c32a2d |
ushort tmp16 = 0;
|
|
Packit |
c32a2d |
byte[] rifftxt = new byte[] { (byte)'R', (byte)'I', (byte)'F', (byte)'F' };
|
|
Packit |
c32a2d |
byte[] wavetxt = new byte[] { (byte)'W', (byte)'A', (byte)'V', (byte)'E' };
|
|
Packit |
c32a2d |
byte[] fmttxt = new byte[] { (byte)'f', (byte)'m', (byte)'t', (byte)' ' };
|
|
Packit |
c32a2d |
byte[] datatxt = new byte[] { (byte)'d', (byte)'a', (byte)'t', (byte)'a' };
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
_out.Write(rifftxt);
|
|
Packit |
c32a2d |
totaloffset = _out.BaseStream.Position;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
_out.Write(tmp32); // total size
|
|
Packit |
c32a2d |
_out.Write(wavetxt);
|
|
Packit |
c32a2d |
_out.Write(fmttxt);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
tmp32 = 16;
|
|
Packit |
c32a2d |
_out.Write(tmp32); // format length
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
tmp16 = (ushort)wavformat;
|
|
Packit |
c32a2d |
_out.Write(tmp16); // format
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
tmp16 = (ushort)channels;
|
|
Packit |
c32a2d |
_out.Write(tmp16); // channels
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
tmp32 = (uint)rate;
|
|
Packit |
c32a2d |
_out.Write(tmp32); // sample rate
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
tmp32 = (uint) (rate * bitspersample / 8 * (int)channels);
|
|
Packit |
c32a2d |
_out.Write(tmp32); // bytes / second
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
tmp16 = (ushort)(bitspersample / 8 * (int)channels); // float 16 or signed int 16
|
|
Packit |
c32a2d |
_out.Write(tmp16); // block align
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
tmp16 = (ushort)bitspersample;
|
|
Packit |
c32a2d |
_out.Write(tmp16); // bits per sample
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
_out.Write(datatxt);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
tmp32 = 0;
|
|
Packit |
c32a2d |
dataoffset = _out.BaseStream.Position;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
_out.Write(tmp32); // data length
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
// rewrite wav header with final length infos
|
|
Packit |
c32a2d |
static void closewav()
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
uint tmp32 = 0;
|
|
Packit |
c32a2d |
// ushort tmp16 = 0;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
int total = (int)_out.BaseStream.Position;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
_out.Seek((int)totaloffset, SeekOrigin.Begin);
|
|
Packit |
c32a2d |
tmp32 = (uint)(total - (totaloffset + 4));
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
_out.Write(tmp32);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
_out.Seek((int)dataoffset, SeekOrigin.Begin);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
tmp32 = (uint)(total - (dataoffset + 4));
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
_out.Write(tmp32);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
// determine correct wav format and bits per sample
|
|
Packit |
c32a2d |
// from mpg123 enc value
|
|
Packit |
c32a2d |
static void initwavformat()
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if ((enc & mpg123clr.mpg.enc.enc_float_64) != 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
bitspersample = 64;
|
|
Packit |
c32a2d |
wavformat = WAVE_FORMAT_IEEE_FLOAT;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
else if ((enc & mpg123clr.mpg.enc.enc_float_32) != 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
bitspersample = 32;
|
|
Packit |
c32a2d |
wavformat = WAVE_FORMAT_IEEE_FLOAT;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
else if ((enc & mpg123clr.mpg.enc.enc_16) != 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
bitspersample = 16;
|
|
Packit |
c32a2d |
wavformat = WAVE_FORMAT_PCM;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
else
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
bitspersample = 8;
|
|
Packit |
c32a2d |
wavformat = WAVE_FORMAT_PCM;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void Main(string[] args)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
const long INBUFF = 16384 * 2 * 2;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
int ret;
|
|
Packit |
c32a2d |
mpg123clr.mpg.ErrorCode state;
|
|
Packit |
c32a2d |
long inoffset,inc = 0;
|
|
Packit |
c32a2d |
long outc = 0;
|
|
Packit |
c32a2d |
byte[] buf = new byte[INBUFF];
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if (args.Length < 2)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
Console.WriteLine("Please supply in and out filenames\n");
|
|
Packit |
c32a2d |
Console.WriteLine("Press any key to exit:");
|
|
Packit |
c32a2d |
while (Console.Read() == 0) ;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
return;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
mpg123clr.mpg.ErrorCode err;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
err = mpg123.mpg123_init();
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
mpg123 mp = new mpg123();
|
|
Packit |
c32a2d |
err = mp.mpg123_new();
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if (err != mpg123clr.mpg.ErrorCode.ok)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
Console.WriteLine("Unable to create mpg123 handle: " + mpg123error.mpg123_plain_strerror(err));
|
|
Packit |
c32a2d |
Console.WriteLine("Press any key to exit:");
|
|
Packit |
c32a2d |
while (Console.Read() == 0) ;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
return;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
mp.mpg123_param(mpg123clr.mpg.parms.verbose, 4, 0);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
err = mp.mpg123_param(mpg123clr.mpg.parms.flags,
|
|
Packit |
c32a2d |
(int) (mpg123clr.mpg.param_flags.fuzzy |
|
|
Packit |
c32a2d |
mpg123clr.mpg.param_flags.seekbuffer |
|
|
Packit |
c32a2d |
mpg123clr.mpg.param_flags.gapless), 0);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if (err != mpg123clr.mpg.ErrorCode.ok)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
Console.WriteLine("Unable to set library options: " + mp.mpg123_strerror());
|
|
Packit |
c32a2d |
Console.WriteLine("Press any key to exit:");
|
|
Packit |
c32a2d |
while (Console.Read() == 0) ;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
return;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
// Let the seek index auto-grow and contain an entry for every frame
|
|
Packit |
c32a2d |
err = mp.mpg123_param(mpg123clr.mpg.parms.index_size, -1, 0);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if (err != mpg123clr.mpg.ErrorCode.ok)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
Console.WriteLine("Unable to set index size: " + mp.mpg123_strerror());
|
|
Packit |
c32a2d |
Console.WriteLine("Press any key to exit:");
|
|
Packit |
c32a2d |
while (Console.Read() == 0) ;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
return;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
// Use float output formats only
|
|
Packit |
c32a2d |
err = mp.mpg123_format_none();
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if (err != mpg123clr.mpg.ErrorCode.ok)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
Console.WriteLine("Unable to disable all output formats: " + mp.mpg123_strerror());
|
|
Packit |
c32a2d |
Console.WriteLine("Press any key to exit:");
|
|
Packit |
c32a2d |
while (Console.Read() == 0) ;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
return;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
int[] rates = mp.mpg123_rates();
|
|
Packit |
c32a2d |
foreach (int rate in rates)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
err = mp.mpg123_format(rate, mpg123clr.mpg.channelcount.both, mpg123clr.mpg.enc.enc_float_32);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if (err != mpg123clr.mpg.ErrorCode.ok)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
Console.WriteLine("Unable to set float output formats: " + mp.mpg123_strerror());
|
|
Packit |
c32a2d |
Console.WriteLine("Press any key to exit:");
|
|
Packit |
c32a2d |
while (Console.Read() == 0) ;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
return;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
err = mp.mpg123_open_feed();
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if (err != mpg123clr.mpg.ErrorCode.ok)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
Console.WriteLine("Unable to open feed: " + mp.mpg123_strerror());
|
|
Packit |
c32a2d |
Console.WriteLine("Press any key to exit:");
|
|
Packit |
c32a2d |
while (Console.Read() == 0) ;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
return;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
string filename = args[0];
|
|
Packit |
c32a2d |
BinaryReader _in = new BinaryReader(File.Open(filename, FileMode.Open));
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
_out = new BinaryWriter(File.Open(args[1], FileMode.Create));
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
while ((ret = (int)(mp.mpg123_feedseek(95000, SeekOrigin.Begin, out inoffset))) == (int)mpg123clr.mpg.ErrorCode.need_more) // equiv to mpg123_feedseek
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
buf = _in.ReadBytes((int)INBUFF);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if (buf.Length <= 0) break;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
inc += buf.Length;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
state = mp.mpg123_feed(buf, (uint)buf.Length);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if (state == mpg123clr.mpg.ErrorCode.err)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
Console.WriteLine("Feed error: " + mp.mpg123_strerror());
|
|
Packit |
c32a2d |
Console.WriteLine("Press any key to exit:");
|
|
Packit |
c32a2d |
while (Console.Read() == 0) ;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
return;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
_in.BaseStream.Seek(inoffset, SeekOrigin.Begin);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
while (true)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
buf = _in.ReadBytes((int)INBUFF);
|
|
Packit |
c32a2d |
if (buf.Length <= 0) break;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
inc += buf.Length;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
err = mp.mpg123_feed(buf, (uint)buf.Length);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
int num;
|
|
Packit |
c32a2d |
uint bytes;
|
|
Packit |
c32a2d |
IntPtr audio;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
while (err != mpg123clr.mpg.ErrorCode.err && err != mpg123clr.mpg.ErrorCode.need_more)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
err = mp.mpg123_decode_frame(out num, out audio, out bytes);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if (err == mpg123clr.mpg.ErrorCode.new_format)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
mp.mpg123_getformat(out rate, out channels, out enc);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
initwavformat();
|
|
Packit |
c32a2d |
initwav();
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
// (Surprisingly?) even though it does a Marshal.Copy it's as efficient as the pointer example below!!!
|
|
Packit |
c32a2d |
if (bytes > 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
byte[] outbuf = new byte[bytes];
|
|
Packit |
c32a2d |
Marshal.Copy(audio, outbuf, 0, (int)bytes);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
_out.Write(outbuf, 0, (int)bytes);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
// Alternative example of direct usage of audio data via pointers - note it needs "unsafe"
|
|
Packit |
c32a2d |
// and I'm fairly sure pointers should be "fixed" first
|
|
Packit |
c32a2d |
// if (bytes > 0)
|
|
Packit |
c32a2d |
// unsafe{
|
|
Packit |
c32a2d |
// byte* p = (byte*)audio;
|
|
Packit |
c32a2d |
// for (int ii = 0; ii < bytes; ii++)
|
|
Packit |
c32a2d |
// _out.Write(*p++);
|
|
Packit |
c32a2d |
// }
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
outc += bytes;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if (err == mpg123clr.mpg.ErrorCode.err)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
Console.WriteLine("Error: " + mp.mpg123_strerror());
|
|
Packit |
c32a2d |
break;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
Console.WriteLine("Finished");
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
closewav();
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
_out.Close();
|
|
Packit |
c32a2d |
_in.Close();
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
mp.mpg123_delete();
|
|
Packit |
c32a2d |
mp.Dispose();
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
mpg123.mpg123_exit();
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|