代码之家  ›  专栏  ›  技术社区  ›  Michal Ciechan

C fmod实时播放流

  •  1
  • Michal Ciechan  · 技术社区  · 16 年前

    我正在尝试实时播放一个流(当它从一个外部源进入时,我不断地向它提供数据),但无论什么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 回复  |  直到 16 年前
        1
  •  1
  •   Mathew Block    16 年前

    如果您希望传输原始数据,而不是PCM数据,您可以通过覆盖fmod文件系统来实现这一点。实现这一点有两种方法,第一种方法是在createSoundexInfo结构中设置文件回调(如果这是针对一个特定文件)。第二个问题是,您可以为所有fmod文件操作全局设置文件系统(如果您希望对多个文件执行此操作)。

    我会解释后一种情况,不过,切换到前一种情况是微不足道的。请参阅“filecallbacks”fmod示例了解完整的示例。

    函数指针:

    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);
    

    Callbacks:

    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...
    
        2
  •  2
  •   Mathew Block    16 年前

    我建议您查看与fmod一起提供的“usercreatedsound”示例,它应该满足您的需要。

    基本思想是定义您希望在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);
    

    这应该足够让你走了,希望这有帮助。

    推荐文章