0
0

Hi, i was wondering how i would go about streaming SPC’s thru FMOD.
right now i am using Waveout and it works just fine. But i want it to
go thru FMOD. This is the code for waveout:

[code:y7h9cozi]
void __stdcall WaveOutDone(HWAVEOUT hwo, u32 umsg, u32 dwInstance, WAVEHDR *wHdr, u32 dwParam2)
{
if (umsg != WOM_DONE || !Wav.ready) return; //’Return if this isn’t an end of buffer message or
//’if we’re no longer ready for more data
Apu.EmuAPU(wHdr->lpData, Wav.bufSize / Wav.fmt.nBlockAlign, 1); //’Emulate SNES APU
//’Send PCM data to output
waveOutWrite(Wav.handle, wHdr, sizeof(WAVEHDR));
}
[/code:y7h9cozi]

Wav.bufSize = (100 * SAMPLE_RATE * 2 * 2) / 1000 ‘//100ms at 32kHz 16-bit stereo
Wav.fmt.nBlockAlign = 2 * (16 >> 3)

All spc’s are 64kb (0x10200) in length.

I already tried it with fmod, but it just crashes. i have no clue if i am even
close. I just need some pointers or tips or some sample code. i looked
at the docs and the stream example but i am still lost.

If you need more info on how i am doing this with waveout
i can post the entire source for the plugin. it is kinda sloppy
but i am working on cleaning it up.

Someone, please help. Thanks.

  • You must to post comments
0
0

It will be usefull if we can see your code when using fmod 😆

  • You must to post comments
0
0

[code:3rvjd7uy]
Function streamcallback(stream As FSOUND_STREAM Ptr, buff As Void Ptr, len As Integer, param As Void Ptr) As F_STREAMCALL

Dim Count As Integer
Dim stereo16bitbuffer As SHORT Ptr
Dim lpData As LPVOID

For Count = 0 To len        '// >>2 = 16bit stereo (4 bytes per sample)
    Apu.EmuAPU(lpData, 12800 / (2 * (16 >> 3)), 1);   //'Emulate SNES APU
  *stereo16bitbuffer++ = (SHORT )lpData    '// left channel
  *stereo16bitbuffer++ = (SHORT )lpData    '// right channel
Next Count

Function = 1

End Function
[/code:3rvjd7uy]

i know this isn’t even close i just don’t know what to do

  • You must to post comments
0
0

Are you trying to make 1 stream out of 1 left and 1 right buffer ????? (i don’t know what SPC’s are, hope this will help you)

This is how i combine 2 channels into 1 stream:
[code:7n8ue2mc]
/*
FMOD needs an interleaved buffer (LRLRLRLR) but the FLAC buffer is (LLLLLLLRRRRRRR)
So we have to mix them in 1 buffer
/
for (blockcount=0,samplecount=0; samplecount<(MyFlacInfo->FLACBufferSize
2), blockcount<MyFlacInfo->FLACBufferSize; samplecount+=2,blockcount++ )
{
for (channel=0; channel<2;channel++)
{
MyFlacInfo->FLACBuff[samplecount+channel]=(short)buffer[channel][blockcount];
}
}[/code:7n8ue2mc]

MyFlacInfo->FLACBufferSize= stereo-samples
blockcount = stereo-samples; sample-count=stereo-samples * 2
FLACBuff = a buffer that get’s copied into a stream-dsp buffer
buffer[channel][sample] = uninterleaved buffer

good luck

chris

  • You must to post comments
0
0

[code:206tuar6]
Function streamcallback(stream As FSOUND_STREAM Ptr, buff As Void Ptr, len As Integer, param As Void Ptr) As F_STREAMCALL

Dim Count As Integer
Dim stereo16bitbuffer As SHORT Ptr
Dim lpData As LPVOID

stereo16bitbuffer = buff  ' you missed this :)
' Render the spc --&gt; pcm
Apu.EmuAPU(lpData, 12800 / (2 * (16 &gt;&gt; 3)), 1);   //'Emulate SNES APU
' then loop throw it
' len must be equal 2 * (16 &gt;&gt; 3)
For Count = 0 To len        '// &gt;&gt;2 = 16bit stereo (4 bytes per sample)
  *stereo16bitbuffer++ = (SHORT )lpData[len]      '// left channel
  *stereo16bitbuffer++ = (SHORT )lpData[len+1]  '// right channel
Next Count

Function = 1

End Function
[/code:206tuar6]

  • You must to post comments
0
0

SPC’s are stereo and the emulator produces stereo sound, i don’t know
how to feed fmod both channels.

I was getting errors so i had to modify it slightly to compile

[code:1gku8smz]
Function streamcallback(stream As FSOUND_STREAM Ptr, buff As VOID Ptr, len As Integer, param As Void Ptr) As F_STREAMCALL

Dim Count As Integer
Dim stereo16bitbuffer As SHORT Ptr
Dim lpData As SHORT Ptr

stereo16bitbuffer = (SHORT*)buff  ' you missed this :)
' Render the spc --&gt; pcm
Apu.EmuAPU(lpData, 12800 / (2 * (16 &gt;&gt; 3)), 1);   //'Emulate SNES APU
' then loop thru it
' len must be equal 2 * (16 &gt;&gt; 3)
For Count = 0 To len        '// &gt;&gt;2 = 16bit stereo (4 bytes per sample)
  *stereo16bitbuffer++ = lpData[len]      '// left channel
  *stereo16bitbuffer++ = lpData[len+1]  '// right channel
Next Count

Function = 1

End Function
[/code:1gku8smz]

but it still crashes… here is the code for creating the stream:

[code:1gku8smz]
Stream = FSOUND_Stream_Create(streamcallback, SizeOf(SpcFile), FSOUND_NORMAL | FSOUND_16BITS | FSOUND_STEREO, SAMPLE_RATE, (void *)12345)
[/code:1gku8smz]

i don’t know what length is, whether it is the entire size or just chunk size
Thanks

  • You must to post comments
0
0

ok… this is the entire code for the waveout version. i am sure
someone knows more about it than me.

[code:2aptnqtf]
‘************************************************************************************************************************
‘************************************************************************************************************************
‘Input plugin module
‘Input plugin for .spc files (snes sound files)
‘************************************************************************************************************************
‘************************************************************************************************************************
$NOMAIN
$Library <winmm.lib>

INCLUDE "types.h"

INCLUDE "SNESAPU.h"

$INCLUDE "..\Includes\InHdr.bas" ‘Input plugin structure
$INCLUDE "..\Includes\xmp_api.bas" ‘XMP API

Type wav_struct
handle As HWAVEOUT ‘Handle to output device
fmt As WAVEFORMATEX ‘Format of sample data being sent
hdr[2] As WAVEHDR ‘Headers for two buffers

ready As b8                         'Device is ready for output

bufSize As u32                  'Size of single output buffer
pBuf[2] As LPVOID               '-&gt; memory allocated for sample data - void  *(pBuf)[2];

End Type

‘Globals
Global XMPInput AS INPUT_STRUCT ‘XMP plugin structure
Global Wav As wav_struct
Global Apu As SAPUFunc
Global SpcFile[0x10200] As s8 ‘Store the .spc file in this buffer
Global sngStart As Single
Global sngStore As Single
Global sngTime As Single
Global intLength As Integer
Global frmMain As HWND ‘XMP main form
Global bPaused As Boolean
‘Global WaveData As LPVOID
‘Global WaveLen As Integer

Const SAMPLE_RATE = 32000

‘Global Wave As LPVOID
‘Global FX_EQ[10] AS Integer

‘***********************************************************************************************************
‘wave out procedures
‘***********************************************************************************************************
Sub WavInit()
Wav.fmt.wFormatTag = WAVE_FORMAT_PCM
Wav.fmt.nChannels = 2
Wav.fmt.nSamplesPerSec = SAMPLE_RATE
Wav.fmt.nAvgBytesPerSec = 2 * (16 >> 3) * SAMPLE_RATE ‘//Stereo – 16-bit – 32kHz
Wav.fmt.nBlockAlign = 2 * (16 >> 3)
Wav.fmt.wBitsPerSample = 16
Wav.fmt.cbSize = 0

Wav.bufSize = (100 * SAMPLE_RATE * 2 * 2) / 1000        '//100ms at 32kHz 16-bit stereo
Wav.pBuf[0] = malloc(Wav.bufSize)
Wav.pBuf[1] = malloc(Wav.bufSize)

End Sub

$CCODE
void __stdcall WaveOutDone(HWAVEOUT hwo, u32 umsg, u32 dwInstance, WAVEHDR *wHdr, u32 dwParam2)
{
if (umsg != WOM_DONE || !Wav.ready) return; //’Return if this isn’t an end of buffer message or
//’if we’re no longer ready for more data
Apu.EmuAPU(wHdr->lpData, Wav.bufSize / Wav.fmt.nBlockAlign, 1); //’Emulate SNES APU
//’Send PCM data to output
waveOutWrite(Wav.handle, wHdr, sizeof(WAVEHDR));
}
$CCODE

Function WavOpen() As b8
Dim error As s32
If Wav.ready Then return 1

'//Open audio device ------------------------
error = waveOutOpen(&amp;Wav.handle, WAVE_MAPPER, &amp;Wav.fmt, (u32)WaveOutDone, 0, CALLBACK_FUNCTION | WAVE_ALLOWSYNC)

If error = MMSYSERR_NOERROR Then
    Wav.ready = 1

    '//Initialize wave blocks ---------------
    memset(&amp;Wav.hdr[0], 0, sizeof(WAVEHDR))
    Wav.hdr[0].dwBufferLength = Wav.bufSize
    Wav.hdr[0].lpData = (s8*)Wav.pBuf[0]
    waveOutPrepareHeader(Wav.handle, &amp;Wav.hdr[0], sizeof(WAVEHDR))
    Wav.hdr[0].dwUser = 0


    memset(&amp;Wav.hdr[1], 0, sizeof(WAVEHDR))
    Wav.hdr[1].dwBufferLength = Wav.bufSize
    Wav.hdr[1].lpData = (s8*)Wav.pBuf[1]
    waveOutPrepareHeader(Wav.handle, &amp;Wav.hdr[1], sizeof(WAVEHDR))
    Wav.hdr[1].dwUser = 1

    '//Start output -------------------------
    Apu.LoadSPCFile(&amp;SpcFile)               '//Load SPC file into APU
    WaveOutDone(Wav.handle, WOM_DONE, 0, &amp;Wav.hdr[0], 0)
    WaveOutDone(Wav.handle, WOM_DONE, 0, &amp;Wav.hdr[1], 0)
End If

Function = Wav.ready

End Function

Sub WavClose()

If Wav.ready Then
    Wav.ready = 0

    waveOutReset(Wav.handle)                '//Tell Windows to reset the output device
    waveOutUnprepareHeader(Wav.handle, &amp;Wav.hdr[0], sizeof(WAVEHDR))
    waveOutUnprepareHeader(Wav.handle, &amp;Wav.hdr[1], sizeof(WAVEHDR))
    waveOutClose(Wav.handle)                '//Close output device

    Wav.handle = NULL
End If

End If

Sub WavQuit()

WavClose()                                  '//Close device if it's open

If Wav.pBuf[0] Then                 '//Free up allocated memory
    free(Wav.pBuf[1])
    free(Wav.pBuf[0])
End If

End Sub

‘Export our header
Function GetXMPInputModule AS LPVOID EXPORT
‘Set up structure
XMPInput.strDescript$ = "SPC700 Player v1.00"
XMPInput.strExt$ = ".spc"
XMPInput.strPre$ = ""
XMPInput.strExtInfo$ = "SNES Files (
.spc)|*.spc"

XMPInput.InInit = Init
XMPInput.InQuit = Quit
XMPInput.InConfig = Config
XMPInput.InOpen = OpenStream
XMPInput.InPlay = PlayStream
XMPInput.InPause = PauseStream
XMPInput.InStop = StopStream
XMPInput.InSysStop = SystemStreamStop

XMPInput.InVolume = SetVolume
XMPInput.InPan = SetPan
XMPInput.InSetEq = SetEQ
XMPInput.InSeek = SeekTo


XMPInput.InGetIcon = InGetIcon
XMPInput.InGetLength = GetLength
XMPInput.InGetTime = GetTime


    XMPInput.InGetWaveSize = WaveSize
    XMPInput.InGetSpecSize = SpecSize
XMPInput.InGetSpectrum = GetSpectrum
XMPInput.InGetWaveform = GetWaveform

'Pointer to Structure
Function = &amp;XMPInput

End Function

Function InGetIcon(strExt$) As Integer
Function = 6
End Function

Function Init(hWindow AS HWND, hInstance AS HINSTANCE) As Integer

frmMain = hWindow


Dim hDLL As HINSTANCE
Dim ver As u32
Dim min As u32
Dim opt As u32


'//==========================================
'// Load SNESAPU.DLL

hDLL = LoadLibrary(&quot;SNESAPU.DLL&quot;)         '//'Try to load SNESAPU
If hDLL Then
    *(void**)&amp;Apu.SNESAPUInfo = (void*)GetProcAddress(hDLL,&quot;SNESAPUInfo&quot;)
    Apu.SNESAPUInfo(&amp;ver, &amp;min, &amp;opt)

    if ver &lt; 0x20000 Or min &gt; 0x20000 Then        '//'Make sure DLL is compatible with v2.0
        MsgBox &quot;This version of SNESAPU.DLL is not compatible.&quot;, &quot;SPC Plug-in&quot;, MB_OK | MB_ICONERROR
        FreeLibrary(hDLL)
        return 1
    End If
Else
    MsgBox &quot;Could not load SNESAPU.DLL&quot;, &quot;SPC Plug-in&quot;, MB_OK | MB_ICONERROR
    return 1
End If

'//Get pointers to needed functions ---------
*(void**)&amp;Apu.LoadSPCFile   = (void*)GetProcAddress(hDLL,&quot;LoadSPCFile&quot;)
*(void**)&amp;Apu.EmuAPU = (void*)GetProcAddress(hDLL,&quot;EmuAPU&quot;)
*(void**)&amp;Apu.SeekAPU   = (void*)GetProcAddress(hDLL,&quot;SeekAPU&quot;)
*(void**)&amp;Apu.SetAPULength = (void*)GetProcAddress(hDLL,&quot;SetAPULength&quot;)



WavInit()   'Start the wave out

Function = 0

End Function

Sub Quit
‘Close the wave out
WavQuit()
End Sub

Sub Config
MsgBox "SPC Player for X Media Player"
End Sub

Function OpenStream (strFile As String) As Integer

StopStream()
Dim fh As HANDLE
Dim l As DWORD

fh = CreateFile(strFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)

'Test for error
If fh = 0 Then
    Function = 1    'Error
End If

ReadFile(fh, &amp;SpcFile, sizeof(SpcFile), &amp;l, NULL)
CloseHandle(fh)

ReadID666Tags(strFile)

Function = 0

End Function

‘Tags
Sub ReadID666Tags(strFile$)
‘Get info
Dim strTitle$
Dim strGame$
Dim strArtist$
Dim strTag$
Dim strTemp$
Dim bytTag As Byte
Dim ListItem As XM_LIST_INFO

Dim FP1 As FILE
Open strFile For Binary As FP1
    'See if there are tags
    Seek FP1, 0x00023
    Get$ FP1, &amp;bytTag, 1
    'Name
    Seek FP1, 0x0002E
    Get$ FP1, strTitle$, 32
    'Game
    Seek FP1, 0x0004E
    Get$ FP1, strGame$, 32

    Seek FP1, 0x000B0
    Get$ FP1, strArtist$, 32

    Seek FP1, 0x000A9
    Get$ FP1, strTemp$, 3

    intLength = Val(strTemp$)
    If intLength &lt;= 10 Then intLength = -1
Close FP1

If bytTag = 26 Then 'Contains tag

    'Set structure
    ListItem.iItem = SendMessage(frmMain, WM_USER, XM_LIST_GETINDEX, 0)
    ListItem.iSubItem = 0

    If Len(strGame$) &gt; 1 And Len(strTitle$) &gt; 1 Then
        strTag$ = Trim$(strGame$) &amp; &quot; - &quot; &amp; Trim$(strTitle$)
        ListItem.szInfo[0] = strTag$
        'Send
        SendMessage(frmMain, WM_USER, XM_LIST_SETTEXT, &amp;ListItem)
    End If
End If

End Sub

‘**************************************** Play back **********************************************
Sub PlayStream
If WavOpen() Then

    sngStart = Timer
    'waveOutSetPitch(Wav.handle, 0x000F8000)
    'Set it's length
    If intLength &lt;&gt; -1 Then Apu.SetAPULength(intLength * SAMPLE_RATE * 2, True)
Else
    MsgBox &quot;Error opening audio device&quot;, &quot;Error&quot;, MB_OK | MB_ICONERROR
End If

End Sub

Sub PauseStream(bytVal AS BYTE)
Dim sngOffSet As Single
bPaused = bytVal
‘See if we should recalc time
If bPaused = False Then
waveOutRestart(Wav.handle)
sngOffSet = Timer – sngStore
sngStart = sngStart + sngOffSet
Else
waveOutPause(Wav.handle)
sngStore = Timer
End If
End Sub

Sub SystemStreamStop()
StopStream()
End Sub

Sub StopStream
If Wav.ready Then
WavClose()
sngStart = 0 ‘Reset counter
bPaused = False
End If
End Sub

Sub SetVolume(intVal)
‘Set the volume for the spc
waveOutSetVolume(Wav.handle, MAKELONG(intVal * 255, intVal * 255) )
End Sub

Sub SetPan(intVal)
End Sub

Sub SeekTo(intVal)
‘Dim sngOffSet As Single
Apu.SeekAPU(intVal, True)’ * SAMPLE_RATE * 2
‘set the new time
‘sngOffSet = intVal * 1000
‘sngStart = sngStart + sngOffSet
End Sub

Function GetLength AS Integer
Function = intLength * 1000 ’60 * SAMPLE_RATE * 2 (60 seconds)
End Function

Function GetTime AS Integer
If bPaused = True Then
‘Do not calc time
Else
sngTime = Timer – sngStart
End If

Function = sngTime * 1000

End Function

‘**************************************** Spectrum **********************************************
Function WaveSize() As Integer
Function = 0’WaveLen
End Function

Function SpecSize() As Integer
Function = 0
End Function

Function GetWaveform AS LPVOID
Function = 0’WaveData
End Function

Function GetSpectrum AS Single PTR
Function = 0
End Function

‘DSP ****************************************************************************************
Sub SetEQ(Index AS Integer, intVal AS Integer)

End Sub
[/code:2aptnqtf]

  • You must to post comments
Showing 6 results
Your Answer

Please first to submit.