C # FMOD Воспроизведение потока в режиме реального времени - PullRequest
1 голос
/ 09 августа 2010

Я пытаюсь воспроизвести поток в режиме реального времени (я продолжаю добавлять к нему данные, полученные из внешнего источника), но независимо от того, что FMOD не хочет продолжать воспроизведение после первой загруженной порции,кажется, что он копирует поток памяти / декодирует его перед воспроизведением, затем во время воспроизведения он больше не использует мой поток.

Я использую следующее для воспроизведения своего потока:

        var exinfo = new FMOD.CREATESOUNDEXINFO();
        exinfo.cbsize = Marshal.SizeOf(exinfo);
        exinfo.length = (uint)_buffer.Length;

        _result = System.createStream(_buffer, MODE.CREATESTREAM | MODE.OPENMEMORY_POINT , ref exinfo, ref _sound);
        FMODErrorCheck(_result);

        _result = System.playSound(FMOD.CHANNELINDEX.FREE, _sound, false, ref _channel);
        FMODErrorCheck(_result);

Но несмотря ни на что, он воспроизводит только объем данных, находящихся в потоке в момент вызова playSound.

Может кто-нибудь знать, как изменить буфер в режиме реального времени?После того, как поток начал играть ...?

Ответы [ 2 ]

2 голосов
/ 09 августа 2010

Я бы порекомендовал вам проверить пример "usercreatedsound", который поставляется с FMOD, он должен делать то, что вам нужно.

Основная идея заключается в том, чтобы определить свойства звука, который вы хотите воспроизвести, в структуре CreateSoundExInfo и предоставить ему обратные вызовы, которые можно использовать для загрузки / потоковой передачи данных из любого места.

Указатель функции:

private FMOD.SOUND_PCMREADCALLBACK pcmreadcallback = new FMOD.SOUND_PCMREADCALLBACK(PCMREADCALLBACK);

Обратный вызов, используемый для заполнения звука FMOD:

private static FMOD.RESULT PCMREADCALLBACK(IntPtr soundraw, IntPtr data, uint datalen)
{
    unsafe
    {  
        short *stereo16bitbuffer = (short *)data.ToPointer();

        // Populate the 'stereo16bitbuffer' with sound data 
    }

    return FMOD_OK;
}

Код для создания звука, который будет использовать обратный вызов:

// ...Usual FMOD initialization code here...

FMOD.CREATESOUNDEXINFO exinfo = new FMOD.CREATESOUNDEXINFO();

// You define your required frequency and channels
exinfo.cbsize            = Marshal.SizeOf(exinfo);
exinfo.length            = frequency * channels * 2 * 5; // *2 for sizeof(short) *5 for 5 seconds
exinfo.numchannels       = (int)channels;
exinfo.defaultfrequency  = (int)frequency;
exinfo.format            = FMOD.SOUND_FORMAT.PCM16;
exinfo.pcmreadcallback   = pcmreadcallback;

result = system.createStream((string)null, (FMOD.MODE.DEFAULT | FMOD.MODE.OPENUSER | FMOD.MODE.LOOP_NORMAL), ref exinfo, ref sound);

Этого должно быть достаточно, чтобы начать, надеюсь, это поможет.

1 голос
/ 09 августа 2010

Если вы хотите передавать потоковые данные, а не данные PCM, вы можете добиться этого, переопределив файловую систему FMOD.Есть два способа добиться этого, первый - установить обратные вызовы файлов в структуре CreateSoundExInfo, если это для одного конкретного файла.Во-вторых, вы можете установить файловую систему глобально для всех файловых операций FMOD (если вы хотите сделать это с несколькими файлами).

Я объясню последний, хотя было бы тривиально переключиться на первый.Обратитесь к примеру FMOD "filecallbacks" для полного примера.

Указатели функций:

private FMOD.FILE_OPENCALLBACK  myopen  = new FMOD.FILE_OPENCALLBACK(OPENCALLBACK);
private FMOD.FILE_CLOSECALLBACK myclose = new FMOD.FILE_CLOSECALLBACK(CLOSECALLBACK);
private FMOD.FILE_READCALLBACK  myread  = new FMOD.FILE_READCALLBACK(READCALLBACK);
private FMOD.FILE_SEEKCALLBACK  myseek  = new FMOD.FILE_SEEKCALLBACK(SEEKCALLBACK);

Обратные вызовы:

private static FMOD.RESULT OPENCALLBACK([MarshalAs(UnmanagedType.LPWStr)]string name, int unicode, ref uint filesize, ref IntPtr handle, ref IntPtr userdata)
{
    // You can ID the file from the name, then do any loading required here
    return FMOD.RESULT.OK;
}

private static FMOD.RESULT CLOSECALLBACK(IntPtr handle, IntPtr userdata)
{
    // Do any closing required here
    return FMOD.RESULT.OK;
}

private static FMOD.RESULT READCALLBACK(IntPtr handle, IntPtr buffer, uint sizebytes, ref uint bytesread, IntPtr userdata)
{
    byte[] readbuffer = new byte[sizebytes];

    // Populate readbuffer here with raw data

    Marshal.Copy(readbuffer, 0, buffer, (int)sizebytes);
    return FMOD.RESULT.OK;
}

private static FMOD.RESULT SEEKCALLBACK(IntPtr handle, int pos, IntPtr userdata)
{
    // Seek your stream to desired position
    return FMOD.RESULT.OK;
}

Реализация:

// Usual init code here...

result = system.setFileSystem(myopen, myclose, myread, myseek, 2048);
ERRCHECK(result);

// Usual create sound code here...
...