PDA

View Full Version : Play a piece of a mp3 stream with mmsystem or directsound??



arthurprs
13-02-2008, 05:13 PM
Hello guys,
is there a way to play a piece of mp3 stream with mmsystem of direct sound (a shoutcast internet stream)

thanks

chronozphere
13-02-2008, 05:54 PM
I wanted to implement that too. But i found out that it was rather hard, so i started to use OGG and OpenAL. :)

You might want to take a look at RazorLame. (http://lame.sourceforge.net/index.php) It is a well-known mp3 encoder/decoder.. i thought that there were pascal headers for it. Dont know where.

arthurprs
13-02-2008, 08:30 PM
lame and razorlame(gui) are encoders :(

arthurprs
13-02-2008, 08:44 PM
i already have the stuff to separate mp3 buffer from icy info, but i need a way to play the mp3 :?

noeska
13-02-2008, 09:58 PM
You might want to try this one:

http://www.mpg123.org/
http://www.mpg123.org/api/mpg123_8h-source.shtml

I believe there was/is an delphi unit available also, but google does not let me find it (anymore).

arthurprs
13-02-2008, 11:05 PM
I think this one will work, now i have to find the headers :( only

chronozphere
14-02-2008, 02:30 PM
lame and razorlame(gui) are encoders :(


I guess not :)



LAME features:

* Many improvements in quality in speed over ISO reference software. See history.
* MPEG1,2 and 2.5 layer III encoding.
* CBR (constant bitrate) and two types of variable bitrate, VBR and ABR.
* Encoding engine can be compiled as a shared library (Linux/UNIX), DLL , Directshow filter or ACM codec (Windows).
* Free format encoding and decoding.
* GPSYCHO: a GPL'd psycho acoustic and noise shaping model.
* Powerful and easy to use presets.
* Quality better than all other encoders at most bitrates.
* Fast! Encodes faster than real time on a PII 266 at highest quality mode.
* MP3x: a GTK/X-Window MP3 frame analyzer for both .mp3 and unencoded audio files.

arthurprs
14-02-2008, 08:37 PM
after 2 days of googling i don't found nothing to help me =/

i tried libmad, but the header i found is incomplete -.-
i don't know how use lame for decoding
i don't find mpg123 header anywhere

i really don't have luck when working with audio

Pyrogine
14-02-2008, 08:49 PM
1. I have some DirectShow that can playback mp3s if you want that. It just works without anything else. But it's DirectShow... it works however and I used it for years for mp3 playback. It's in a nice and easy to use API.

2. If you have something that can decode the mp3, then you can just create a player using the framework code I sent you. Look at the ogg player class as a guide.

arthurprs
14-02-2008, 09:34 PM
1. I have some DirectShow that can playback mp3s if you want that. It just works without anything else. But it's DirectShow... it works however and I used it for years for mp3 playback. It's in a nice and easy to use API.

2. If you have something that can decode the mp3, then you can just create a player using the framework code I sent you. Look at the ogg player class as a guide.

1. Directshow plays fine mp3, but not in my case (incomplete streams ( frominternet radio))

2. I can't find anything for pascal :(

Pyrogine
14-02-2008, 10:04 PM
look for my email to you.

chronozphere
15-02-2008, 07:57 AM
I'm quite interested too. Can you also mail/PM it to me? :razz:

marmin
15-02-2008, 11:35 AM
The fact that DirectX is o crappy with playing ogg (ogg and Microoft- what's that?) and mp3 is one of the reaons why I now use SDL. Playing and mixing ound FX and mp3 treams is so easy.

Pyrogine
15-02-2008, 02:02 PM
I quickly looked at mpg123 and it seems like making a Delphi header for the DLL should not be too hard. I've not used this decoder so I have no clue to the performance or any thing. On first look it seems simple enough. But, maybe if this is combined with my DirectX audio player framework you may have a DirectX mp3 solution as well.

arthurprs
15-02-2008, 04:32 PM
I have converted the headers but im having strange problems :?

with the dynamic linking i get error on mpg123_new (the program closes)

with static linking i get error on mpg123_info (the program closes)

dynamic linking
http://pastebin.com/m2f53c130

static linking
http://pastebin.com/m47e4f72b

code

var
error : Longint;
mp3handle : Pmpg123_handle;
v1 : Pmpg123_id3v1;
v2 : Pmpg123_id3v2;
info : Tmpg123_frameinfo;
s : PChar;

function checkerror : Boolean;
begin
Result := mpg123_errcode(mp3handle) = 0;
Writeln(mpg123_strerror(mp3handle));
end;

begin
if mpg123_init <> mpg123_ok then Halt;
s &#58;= mpg123_decoders&#40;&#41;^;
mp3handle &#58;= mpg123_new&#40;s,@error&#41;;
checkerror;
mpg123_open&#40;mp3handle,'mp3.mp3'&#41;;
checkerror;
v1 &#58;= new&#40;Pmpg123_id3v1&#41;;
v2 &#58;= new&#40;Pmpg123_id3v2&#41;;
mpg123_info&#40;mp3handle,@info&#41;;

mpg123_id3_&#40;mp3handle,v1,v2&#41;;
checkerror;
mpg123_close&#40;mp3handle&#41;;


mpg123_exit;
Readln;
end.

noeska
15-02-2008, 05:07 PM
is s giving one decoder as pchar or a list of decoders as an array of pchar? If it is a list you should pick one from the list and feed that to the _new.

See: http://www.mpg123.org/api/group__mpg123__decoder.shtml#g8e64dd89e0b9cbb74d46 871787956966

arthurprs
15-02-2008, 07:25 PM
i corrected it using 'MMX' (one of the results)


now i will try to craft a pseudo mp3player, to understand it better

arthurprs
15-02-2008, 10:27 PM
how do i know the amount of sleep(ms) after filling one of the buffer half ?

im getting problems, the sound is breaking sometime :(

arthurprs
16-02-2008, 04:01 AM
i got it :D

Pyrogine
16-02-2008, 05:32 AM
was your mix buffer too small?

chronozphere
16-02-2008, 11:34 AM
@Arthurprs: Can you post your working code? .. i would love to see how to play MP3 in pascal. :razz: I never got that working.

arthurprs
16-02-2008, 02:16 PM
was your mix buffer too small?

no the update method was flawed its best to use an event notification (when the buffers hits 25% and 75%)



chronozphere :~
I still having problems with dymanic linking, when i solve it i will create a new thread with the working header

Brainer
16-02-2008, 02:51 PM
This will probably be interesting for you:
http://www.fileshost.com/en/file/33932/mp3component-zip.html

arthurprs
16-02-2008, 03:23 PM
there is any theory about a lib that don't work correctly when using Dynamic linking (LoadLibrary and GetProcAddress) ?

noeska
16-02-2008, 03:27 PM
what is the problem with the dynamic version? I remind having problems with dynamic usage of the openal lib due to Case Sensitivnes of the commands e.g. nameoffunction is different from NameOfFunction.

arthurprs
16-02-2008, 04:23 PM
what is the problem with the dynamic version? I remind having problems with dynamic usage of the openal lib due to Case Sensitivnes of the commands e.g. nameoffunction is different from NameOfFunction.

The function appers to don't receiving the correct parameters, not sure

chronozphere
16-02-2008, 05:14 PM
So the static version does work but the dynamic doesn't?? :?

I worked with openAL and i had some problems with the dynamic version. It were the same problems Noeska talks about. You should make sure that every function you are calling is not NIL and is properly assigned (right proc-var contains right function, look at the OpenAL unit).

This is the only possible difference between dynamic and static loading that i can think of. :?

arthurprs
16-02-2008, 06:42 PM
So the static version does work but the dynamic doesn't?? :?

I worked with openAL and i had some problems with the dynamic version. It were the same problems Noeska talks about. You should make sure that every function you are calling is not NIL and is properly assigned (right proc-var contains right function, look at the OpenAL unit).

This is the only possible difference between dynamic and static loading that i can think of. :?

i created a method to check all them, all funcs have correct pointers

:(

im confused

chronozphere
16-02-2008, 11:41 PM
> Do you have the latest OpenAL version, and do you link the correct OpenAL.dll?

> Are the calling conventions correct? each function should have a cdecl calling convention. :)

Can you explain what goes wrong when the DLL is dynamicly linked. What kind of code are you trying to run, and which function call do you think causes the error?

arthurprs
16-02-2008, 11:54 PM
> Do you have the latest OpenAL version, and do you ]cdecl[/b] calling convention. :)

Can you explain what goes wrong when the DLL is dynamicly linked. What kind of code are you trying to run, and which function call do you think causes the error?

im using direct sound :)

the dll with the problem, is the mp3 decoder one

i still can't find anything wrong http://pastebin.com/m2f53c130

Pyrogine
17-02-2008, 08:15 AM
make sure your calling convention is correct. It will most likely be cdecl if nothing else is specified. Looking at your code, it looks like you are using register convention on the Delphi side and that c lib will know nothing about this. It will crash.

chronozphere
17-02-2008, 10:02 AM
im using direct sound Smile :)

Oops :oops: I had similair probs with OpenAL so i thought you used OpenAL.

Like i and jarrod said, it has probably to do with the calling convention of one or more functions you are trying to use. :)

arthurprs
17-02-2008, 01:31 PM
make sure your calling convention is correct. It will most likely be cdecl if nothing else is specified. Looking at your code, it looks like you are using register convention on the Delphi side and that c lib will know nothing about this. It will crash.

SHIT, im so idiot, i forget the cdecl; on the dymamic variables -.-

now it works perfectly :D

chronozphere
17-02-2008, 03:41 PM
Can you plz post your working code now? :razz:

arthurprs
17-02-2008, 05:15 PM
unit mp3stream;

interface

uses
SysUtils, Windows, Classes, DirectSound, MMSystem, mpg123;


type
TMP3 = class(TThread)
public
FFileName: string;
Fhandle: Pmpg123_handle;
Frate: Integer;
Fchannels: Integer;
Fencoding: Integer;
Fbuffersize: Cardinal;

FPlaying: Boolean;
public
procedure updatebuffer;
procedure prebuffer;
procedure Play;
procedure Stop;
procedure Execute; override;
public
function initmpg123: Boolean;
constructor Create(const filepath: string);
destructor Destroy; override;
end;

implementation

uses
main;

{ TMP3 }

constructor TMP3.Create(const filepath: string);
begin
inherited Create(True);
FFileName := filepath;
Priority := tpTimeCritical;
if FileExists(FFileName) then
initmpg123;
end;

destructor TMP3.Destroy;
begin
mpg123_close(Fhandle);
mpg123_exit;
inherited;
end;

procedure TMP3.Execute;
var
critical : RTL_CRITICAL_SECTION;
begin
InitializeCriticalSection(critical);
EnterCriticalSection(critical);
repeat
updatebuffer;
Sleep(300);
until Terminated;
LeaveCriticalSection(critical);
DeleteCriticalSection(critical);
end;

function TMP3.initmpg123: Boolean;
begin
Result := False;
if mpg123_init <> 0 then Exit;

Fhandle := mpg123_new('MMX', nil); // MMX is common
if Fhandle = nil then Exit;
mpg123_open(Fhandle, PChar(FFileName));
mpg123_getformat(Fhandle, @Frate, @Fchannels, @Fencoding);
mpg123_format_none(Fhandle);
mpg123_format(Fhandle, Frate, Fchannels, Fencoding);
end;

procedure TMP3.Play;
begin
prebuffer;
resume;
sbuffer.Play(0, 0, DSBPLAY_LOOPING);
end;

procedure TMP3.Stop;
begin
Suspend;
sbuffer.Stop;
end;

procedure TMP3.prebuffer;
var
buffer: PByte;
size: Cardinal;
d: Cardinal;
begin
Fbuffersize := wfm.nAvgBytesPerSec;

sbuffer.Lock(0, Fbuffersize, @buffer, @size, nil, nil, 0);

mpg123_read(Fhandle, buffer, size, @d);

sbuffer.Unlock(buffer, size, nil, 0);
end;

procedure TMP3.updatebuffer;
var
buffer: PByte;
size: Cardinal;
d: Cardinal;
e : Cardinal;
section : Cardinal;
begin
e := WaitForMultipleObjects(2,@events,False,0);

if e = 0 then
section := 1
else
if e = 1 then
section := 0
else
exit;



sbuffer.Lock(section*Fbuffersize,Fbuffersize,@buff er,@size,nil,nil,0);

mpg123_read(Fhandle, buffer, size, @d);

sbuffer.Unlock(buffer,size,nil,0);
end;

end.

unit main;

interface

uses
SysUtils,
Windows,
DirectSound,
MMSystem,
Classes,
mp3stream;

var
DS: IDirectSound8;
dsnotify : IDirectSoundNotify8;
events : array [0..1] of Cardinal;
notifs : array [0..1] of TDSBPOSITIONNOTIFY;

sbuffer: IDirectSoundBuffer;

wfm: TWAVEFORMATEX;
desc: TDSBUFFERDESC;

mp3: TMP3;

procedure RUN;

implementation

procedure RUN;
begin
IsMultiThread := True;
SetConsoleTitle('APP');

mp3 := TMP3.Create('mp3.mp3');

if DirectSoundCreate8(nil, DS, nil) <> DS_OK then Exit;

if DS.SetCooperativeLevel(FindWindow(nil, 'APP'), DSSCL_NORMAL) <> DS_OK then Exit; ;

FillChar(wfm, SizeOf(wfm), 0);
wfm.cbSize := SizeOf(wfm);
wfm.nChannels := mp3.Fchannels;
wfm.wBitsPerSample := 16;
wfm.nSamplesPerSec := mp3.Frate;
wfm.nAvgBytesPerSec := wfm.nSamplesPerSec * wfm.nChannels * 2;
wfm.nBlockAlign := 2 * wfm.nChannels;
wfm.wFormatTag := WAVE_FORMAT_PCM;

// set up the buffer
desc.dwSize := SizeOf(desc);
desc.dwFlags := 0;
desc.lpwfxFormat := @wfm;
desc.dwReserved := 0;
desc.dwBufferBytes := wfm.nAvgBytesPerSec * 2;

desc.dwFlags :=
DSBCAPS_STATIC or
DSBCAPS_CTRLPOSITIONNOTIFY or
DSBCAPS_CTRLVOLUME or
DSBCAPS_GLOBALFOCUS ;

ds.CreateSoundBuffer(desc,sbuffer,nil);
sbuffer.QueryInterface(IID_IDirectSoundNotify8,dsn otify);

events[0] := CreateEvent(nil,False,False,'0.25 played');;
events[1] := CreateEvent(nil,False,False,'0.75 played');
notifs[0].hEventNotify := events[0];
notifs[0].dwOffset := wfm.nAvgBytesPerSec div 2;
notifs[1].hEventNotify := events[1];
notifs[1].dwOffset := (wfm.nAvgBytesPerSec * 3) div 2;

if dsnotify.SetNotificationPositions(2,@notifs) <> DS_OK then Exit;

mp3.Play;


sleep(1000 * 60 * 1);


mp3.Stop;

CloseHandle(events[0]);
CloseHandle(events[1]);

dsnotify := nil;
sbuffer := nil;
DS := nil;

mp3.Free;
end;

end.

lordzero
17-02-2008, 05:52 PM
for commercial projects i need use ogg... because to use mp3 i need pay royalty...

you have some suggestion?

chronozphere
17-02-2008, 06:29 PM
I have a suggestion :)

You should take a look at the ogg player example on noeska's site

http://www.noeska.com/doal/tutorials.aspx

The player itsself is really simple. It even doesn't have a Stop function, but i guess you are able to write one. It uses OpenAL instead of DirectSound but that shouldn't be a problem. I think openAL is much easier. :)

This is a pascal version of an article that was posted on devmaster.net, about playing ogg with OpenAL. You might want to take a look at it. :)

@ArthurPrs: Thanx alot for posting the code. Can you update the mpg123 header you posted on pastebin, so we can have a working version? Thanx again :)

Huehnerschaender
17-02-2008, 06:56 PM
to play ogg-files I use Squall, which is free to use and offers everything you need, including 3D sound.

arthurprs
17-02-2008, 07:52 PM
http://pastebin.com/m7122488b

here it is, the only dif is the calling convention;

Pyrogine
17-02-2008, 08:27 PM
Here is my Ogg Sample & Music Playback Engine

* it is based on a early version of PyroAudio
* used DirectSound
* full source code
* load/play/mix ogg samples
* play streaming ogg
* reserve channels
* thread updates audio in the background
* load up to 256 samples and can mix up to 32 channels
* Include a music player where you can play a directory full of ogg files
* Include a audio player demo
* add OggAudio.pas to your uses statement. The Audio object will be created/destroyed automatically.

In this version globalfocus for sample is control by DirectSound which for most purposes works ok. Ideally you would want to manually control globalfocus yourself. I have this working for the streaming music. See how it's implemented to do the same for the samples.

OggAudio Engine (http://www.pyrogine.com/temp/oggaudio.zip)

arthurprs
18-02-2008, 03:41 AM
Here is my Ogg Sample & Music Playback Engine

* it is based on a early version of PyroAudio
* used DirectSound
* full source code
* load/play/mix ogg samples
* play streaming ogg
* reserve channels
* thread updates audio in the background
* load up to 256 samples and can mix up to 32 channels
* Include a music player where you can play a directory full of ogg files
* Include a audio player demo
* add OggAudio.pas to your uses statement. The Audio object will be created/destroed automatically.

In this version globalfocus for sample is control by DirectSound which for most purposes works ok. Ideally you would want to manually control globalfocus yourself. I have this working for the streaming music. See how it's implemented to do the same for the samples.

OggAudio Engine (http://www.pyrogine.com/temp/oggaudio.zip)

nice =D

ps: keeping synchronization with the http stream is like HELL

lordzero
18-02-2008, 02:14 PM
cool man..

seems that i found one solution... :)

lordzero
18-02-2008, 02:15 PM
and about the file license.txt?

i cant found it...

can be used for free on commercial projects?

Pyrogine
18-02-2008, 03:32 PM
arthurprs
Thanks. Yea this is hard to do. I've not tried to do it yet, but I have some thoughts. Email me when you can.


lordzero
Thanks. Oh sorry about that... yea you can use it in free and commercial projects. If you improve/fix/change it be sure to send me a copy.

noeska
18-02-2008, 10:04 PM
Thanks to arthurprs for converting the mpg123 units.
It inspired me to pick up my OpenAl project again and make an mp3 for it using your example.
I need to clean up some things so i hope to publish an example tomorow.
Under what license comes your header conversion? Public Domain or Like my openal unit (mpl/lgpl dual license)?

arthurprs
19-02-2008, 08:38 PM
Thanks to arthurprs for converting the mpg123 units.
It inspired me to pick up my OpenAl project again and make an mp3 for it using your example.
I need to clean up some things so i hope to publish an example tomorow.
Under what license comes your header conversion? Public Domain or Like my openal unit (mpl/lgpl dual license)?

LGPL, soon it will be on mpg123 page

noeska
19-02-2008, 08:51 PM
Here is the openal example for mpg123.

http://www.noeska.net/downloads/OpenALMp3Play.zip

http://www.noeska.net/downloads/openal.zip bugfixed openal unit.

I removed the original posting as i was unable to post the complete sourcecode listing here.

arthurprs
19-02-2008, 08:57 PM
where are TMP3.updatebuffer ? :?

noeska
19-02-2008, 09:01 PM
must be a maximum to the post length?

Look at the zip file 2 posts up. That should contain the complete listing.

noeska
19-02-2008, 09:10 PM
I do have a license question with the unit sourcecode being under lgpl also. Does not this mean that the program using the unit also fall under lgpl? Or am i being paranoid then? With dynamic linking to an library under lgpl your program does not fall under lgpl. That is why choose to release the unit under a dual license. (may be overkill).

arthurprs
19-02-2008, 11:04 PM
[quote="noeska"]I do have a license question with the unit sourcecode being under lgpl also. Does not this mean that the program using the unit also fall under lgpl? Or am i being paranoid then? With dynamic ]

no its not necessary

"The main difference between the GPL and the LGPL is that the latter can be linked to (in the case of a library, 'used by') a non-(L)GPLed program, which may be free software or proprietary software"

http://en.wikipedia.org/wiki/LGPL

noeska
20-02-2008, 07:14 PM
Ok, so it is legal to use your unit in an closed source application as long as i tell where your unit is? What troubes me that your unit will be staticly linked into the application.

Also made a slightly modified mp3 player for openal. It now plays an mp3 until the end of it and then exits. http://www.noeska.net/downloads/OpenALMp3Play2.zip

arthurprs
20-02-2008, 09:01 PM
Ok, so it is legal to use your unit in an closed source application as long as i tell where your unit is? What troubes me that your unit will be staticly ]http://www.noeska.net/downloads/OpenALMp3Play2.zip[/url]

yes, how is this? "staticly linked into the application"

noeska
20-02-2008, 10:17 PM
oops that is an typo from my side i mean statically linked. As that the unit is/becomes part of the executeable. LGPL states that then "Alternatively, a statically linked library is allowed if either source code or linkable object files are provided.". So although you dynamically link to the mpg123 dll you also place lgpl code directly into your exe.
Also read term 3 of http://www.gnu.org/copyleft/lesser.html it is allowed to place a header file you use to dynamically link to the lgpl code under another license as long as it is does not contain code from the lgpl library. So to avoid the hasle i made the openal unit a dual license.