libopenmpt bindings

Headers, Bindings, Libraries for use with FreeBASIC, Please include example of use to help ensure they are tested and usable.
Post Reply
Jojo
Posts: 107
Joined: Jan 04, 2006 20:02
Contact:

libopenmpt bindings

Post by Jojo »

Hi all,
I have moved away from FreeBASIC years ago pretty much at the same time when I started working on OpenMPT. However, I have not completely forgotten about my past and thus I have created bindings for FreeBASIC for libopenmpt, a cross-platform module playing library.
I'll also write a small example for playing modules with libopenmpt + portaudio in the upcoming days.
libopenmpt can easily be compiled using the provided makefile on Linux. On Windows you may also use some precompiled binaries in case you have no C++ compiler handy.
The headers were mostly translated with FBFrog, with a couple of fixes and useful additions (such as automatic memory management for the returned ZStrings). I'll try to keep the headers up-to-date whenever the original C headers change.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: libopenmpt bindings

Post by D.J.Peters »

You know libdumb 0.9.3 ?

Joshy
Jojo
Posts: 107
Joined: Jan 04, 2006 20:02
Contact:

Re: libopenmpt bindings

Post by Jojo »

Of course I know DUMB, but what does that have to do with anything? Naturally I am biased but considering that a large part of modules are made with OpenMPT these days, libopenmpt is the best solution for playing most of these as they are going to sound 100% the same as in the tracker.
Do you realize that DUMB 0.9.3 is about ten years old and thus greatly lacks behind libopenmpt in terms of playback quality? Unless of course you mean kode54's newer version which is actively maintained but for some reason still contains the original readme file with the original version number from ten years back, despite the actual library version being 1.0.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: libopenmpt bindings

Post by D.J.Peters »

Come down It was only a question / hint.

It's nice to have more than one mod player bindings for FreeBASIC.

So share your work with us.

Joshy
Jojo
Posts: 107
Joined: Jan 04, 2006 20:02
Contact:

Re: libopenmpt bindings

Post by Jojo »

D.J.Peters wrote:Come down It was only a question / hint.
Sorry but as a tracker / playback library developer I pretty much allergic against outdated playback libraries because all of them are broken in one way or another. The latest DUMB builds (by kode54) are great, but 0.9.3 is definitely not and nobody should use it, ever. Similarly, mikmod and libmodplug should be avoided because their playback code has been more or less unmaintained for the last ten years. If you are still using DUMB 0.9.3 you should seriously consider upgrading to the latest version.
Jojo
Posts: 107
Joined: Jan 04, 2006 20:02
Contact:

Re: libopenmpt bindings

Post by Jojo »

Here's an example for possible inclusion with FreeBASIC. It plays one module from memory and loads another from disk (assuming that it's placed in examples\sound\libopenmpt in the FreeBASIC package). It requires the PortAudio library for playback. Note that the current libopenmpt version as it can be currently found on our website won't play the second file because that version does not include an MO3 decoder yet. However, the next release (due by the end of the year) will support MO3. Until then, you either have to compile a more recent version of libopenmpt yourself or play another module, like dne_trtn.mod from the FreeBASIC package. ;)

Code: Select all

' libopenmpt example for FreeBASIC
' This example uses libopenmpt to decode some modules and PortAudio to play them.

#Include Once "libopenmpt.bi"
#Include Once "portaudio.bi"

#define BUFFERSIZE 480
#define SAMPLERATE 48000

Dim As Short LeftBuf(BUFFERSIZE)
Dim As Short RightBuf(BUFFERSIZE)
Dim As Short Const Ptr buffers(2) = { @LeftBuf(0), @RightBuf(0) }

' A little example module stored in memory :)
' This tiny module has been composed by FireLight
' and can be downloaded at http://modarchive.org/module.php?69172
Dim As Byte songstatic(...) = _
{ _
    &H49,&H4D,&H50,&H4D,&H53,&H69,&H6D,&H70,&H73,&H6F,&H6E, _
    &H73,&H20,&H69,&H6E,&H20,&H63,&H68,&H69,&H70,&H20,&H6C, _
    &H61,&H6E,&H64,&H21,&H00,&H00,&H00,&H00,&H04,&H10,&H02, _
    &H00,&H00,&H00,&H01,&H00,&H01,&H00,&H25,&H51,&H14,&H02, _
    &H41,&H00,&H04,&H00,&H80,&H30,&H05,&H7D,&H80,&H00,&H00, _
    &H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H20,&H0A, _
    &H00,&H00,&H19,&H33,&H47,&H87,&H53,&H09,&H15,&H02,&H00, _
    &HA0,&HA0,&HA0,&HA0,&HA0,&HA0,&HA0,&H49,&H4D,&H50,&H53, _
    &H53,&H69,&H6E,&H65,&H2E,&H30,&H30,&H33,&H00,&H00,&H00, _
    &H00,&H00,&H40,&H19,&H40,&H42,&H79,&H20,&H46,&H69,&H72, _
    &H65,&H4C,&H69,&H67,&H68,&H74,&H2E,&H2E,&H73,&H6D,&H61, _
    &H6C,&H6C,&H65,&H73,&H74,&H20,&H73,&H33,&H00,&H01,&H20, _
    &H10,&H00,&H00,&H00,&H04,&H00,&H00,&H00,&H10,&H00,&H00, _
    &H00,&HAB,&H20,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00, _
    &H00,&H00,&H41,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H40, _
    &H40,&H40,&H40,&H40,&H40,&H40,&H40,&H40,&H40,&H40,&H40, _
    &H40,&H40,&H40,&H40,&H40,&H40,&H40,&H40,&H40,&H40,&H40, _
    &H40,&H40,&H40,&H40,&H40,&H00,&HFF,&H54,&H00,&H00,&H00, _
    &HCA,&H00,&H00,&H00,&HA2,&H00,&H27,&H00,&H00,&H00,&H00, _
    &H00,&H81,&H0B,&H3C,&H01,&H13,&HB0,&H00,&H00,&H81,&H38, _
    &H0A,&H46,&H00,&H81,&H84,&H20,&H00,&H81,&HB0,&H00,&H81, _
    &HC0,&H00,&H81,&H29,&H36,&H08,&HA3,&H00,&H81,&H80,&H00, _
    &H01,&H00,&H81,&H08,&H05,&H0F,&H00,&H81,&H29,&H3C,&H0A, _
    &H46,&H00,&H81,&HC0,&H00,&H81,&HB0,&H00,&H81,&HC0,&H00, _
    &H81,&HB0,&H00,&H81,&H08,&H13,&HB3,&H00,&H81,&H38,&H01, _
    &H1F,&H00,&H81,&H29,&H40,&H01,&H12,&H00,&H81,&H25,&H42, _
    &HCD,&H00,&H81,&H29,&H45,&H01,&H0C,&H00,&H01,&H43,&H01, _
    &H1F,&H00,&H01,&H40,&H01,&H12,&H00,&H81,&H61,&H3C,&H00, _
    &H81,&H29,&H37,&H01,&H0C,&H00,&H01,&H36,&H01,&H0A,&H00, _
    &H81,&H70,&H00,&H81,&H34,&HCE,&H00,&H81,&H29,&H37,&H01, _
    &H1F,&H00,&H81,&H40,&H00,&H81,&H29,&H36,&H01,&H0A,&H00, _
    &H81,&H34,&HCC,&H00,&H81,&H70,&H00,&H81,&H61,&H37,&H00, _
    &H81,&H29,&H3B,&H01,&H05,&H00,&H81,&H40,&H00,&H81,&H04, _
    &HCD,&H00,&H01,&HCE,&H00,&H01,&HCF,&H00,&H00 _
}


If(Pa_Initialize() <> paNoError) Then
	Print "Pa_Initialize() failed."
	Sleep
	End
EndIf

Dim As PaStream Ptr stream = 0
If((Pa_OpenDefaultStream(@stream, 0, 2, paInt16 Or paNonInterleaved, SAMPLERATE, paFramesPerBufferUnspecified, NULL, NULL) <> paNoError) OrElse (stream = 0)) Then
	Print "Pa_OpenDefaultStream() failed."
	Pa_Terminate()
	Sleep
	End
EndIf

If(Pa_StartStream(stream) <> paNoError) Then
	Print "Pa_StartStream() failed."
	Pa_Terminate()
	Sleep
	End
EndIf

Cls

If(HiWord(openmpt_get_library_version()) < HiWord(OPENMPT_API_VERSION)) Then
	Print "libopenmpt API version does not match the header version (" & OPENMPT_API_VERSION_STRING & ")!"
	Sleep
	End
EndIf

Print "Welcome to libopenmpt " & openmpt_get_string(OPENMPT_STRING_CORE_VERSION)

Print "Example 1: Loading module from memory."
Print "Press ESC when you're starting to get bored of this tune."
' Load it
Var module = openmpt_module_create_from_memory(@songstatic(0), UBound(songstatic))
' Loop it endlessly
openmpt_module_set_repeat_count(module, -1)
Do
	Locate 5, 1, 0
	Print "Order: " & openmpt_module_get_current_order(module) & " / " & openmpt_module_get_num_orders(module)
	Print "Pattern: " & openmpt_module_get_current_pattern(module) & ", row " & openmpt_module_get_current_row(module) & " / " & openmpt_module_get_pattern_num_rows(module, openmpt_module_get_current_pattern(module)) & "     "

	' Render up to BUFFERSIZE samples...
	Var count = openmpt_module_read_stereo(module, SAMPLERATE, BUFFERSIZE, @LeftBuf(0), @RightBuf(0))
	if(count = 0) Then Exit Do
	' ...and send them to the sound device.
	Pa_WriteStream(stream, @buffers(0), count)
Loop Until InKey = Chr(27)
' Never forget to destroy a module after playing it!
openmpt_module_destroy(module)

Print
Print "Next, we are going to play a module from a file."
Sleep

Cls
Print "Loading... ";
module = openmpt_module_create_from_filename("../data/example.mo3")
If(module = 0) Then
	Print "Unable to load module!"
	Sleep
	End
EndIf
Print "Done."

Print "Playing """ & openmpt_module_get_metadata(module, "title") & """, duration: " & CInt(openmpt_module_get_duration_seconds(module)) & " seconds."
Print "Press left and right cursor keys to jump around in the song."

Dim As String key
Var num_orders = openmpt_module_get_num_orders(module) 
Do
	Locate 5, 1
	Var order = openmpt_module_get_current_order(module)
	Print "Order: " & order & " / " & num_orders & "    "
	Print "Pattern: " & openmpt_module_get_current_pattern(module) & ", row " & openmpt_module_get_current_row(module) & " / " & openmpt_module_get_pattern_num_rows(module, openmpt_module_get_current_pattern(module)) & "    "

	' Again, render up to BUFFERSIZE samples...
	Var count = openmpt_module_read_stereo(module, SAMPLERATE, BUFFERSIZE, @LeftBuf(0), @RightBuf(0))
	if(count = 0) Then Exit Do
	' ...and send them to the sound device.
	Pa_WriteStream(stream, @buffers(0), count)
	
	key = InKey
	If(key = Chr(255, 75)) Then
		' If we jump backwards into a separator pattern, we need to jump back another time, otherwise we will just repeat the current pattern
		Do
			order -= 1
			If(order < 0) Then order = 0
			openmpt_module_set_position_order_row(module, order, 0)
		Loop Until order <= 0 OrElse openmpt_module_get_pattern_num_rows(module, openmpt_module_get_order_pattern(module, order)) <> 0
	ElseIf(key = Chr(255, 77)) Then
		openmpt_module_set_position_order_row(module, order + 1, 0)
	EndIf
Loop Until key = Chr(27)
openmpt_module_destroy(module)

If(Pa_IsStreamActive(stream) = 1) Then Pa_StopStream(stream)
Pa_CloseStream(stream)

Pa_Terminate()
Post Reply