• DirectSound学习笔记(7):缓冲区操作


    填充和播放静态缓冲区

    向一个静态缓冲区载入数据是包含三个步骤:
    1. 使用IDirectSoundBuffer8::Lock将整个缓冲区锁定。你指定缓冲区中你打算开始写的偏移位置(通常为0),并返回该点的内存地址。
    2. 使用标准的内存拷贝程序将音频数据写入返回的地址中。
    3. 使用IDirectSoundBuffer8::Unlock为缓冲区解锁。

    下面的例子显示了这些步骤,其中lpdsbStatic是一个IDirectSoundBuffer8接口指针,pbData是一个数据源地址:

    LPVOID lpvWrite;
    DWORD  dwLength;

    if (DS_OK == lpdsbStatic->Lock(
          
    0,          // Offset at which to start lock.
          0,          // Size of lock; ignored because of flag.
          &lpvWrite,  // Gets address of first part of lock.
          &dwLength,  // Gets size of first part of lock.
          NULL,       // Address of wraparound not needed. 
          NULL,       // Size of wraparound not needed.
          DSBLOCK_ENTIREBUFFER))  // Flag.
    {
      memcpy(lpvWrite, pbData, dwLength);
      lpdsbStatic
    ->Unlock(
          lpvWrite,   
    // Address of lock start.
          dwLength,   // Size of lock.
          NULL,       // No wraparound portion.
          0);         // No wraparound size.
    }

    else
    (
      ErrorHandler();  
    // Add error-handling here.
    }

    调用IDirectSoundBuffer8::Play播放缓冲区,如下面的例子:

    lpdsbStatic->SetCurrentPosition(0);
    HRESULT hr 
    = lpdsbStatic->Play(
        
    0,  // Unused.
        0,  // Priority for voice management.
        0); // Flags.
    if (FAILED(hr))
    (
      ErrorHandler();  
    // Add error-handling here.
    }

    因为这个例子中没有设置 DSBPLAY_LOOPING标识,当缓冲区到达末尾时自动停止播放。你也可以使用IDirectSoundBuffer8::Stop过早停止它。当 你过早停止一个缓冲区时,播放指针的位置仍然停留在那里。因此例子中调用 IDirectSoundBuffer8::SetCurrentPosition,确保缓冲区从起始位置播放。

    使用流缓冲区

    一个流缓冲区播放一长段声音时,不能一次将所有声音装 入缓冲区。当缓冲区播放时,旧数据周期性地被新数据替换。调用IDirectSoundBuffer8::Play方法播放流缓冲区,设置dsFlags 参数为DSBPLAY_LOOPING。调用IDirectSoundBuffer8::Stop方法停止播放。这个方法立即停止缓冲区,因此你需要确保 所有数据已经被播放。这个可以通过轮流检查播放位置或设置通知位置来实现。

    流入一个缓冲区需要以下步骤:
    1. 确定缓冲区是否已做好接收新数据的准备。这个可以通过轮流检查播放指针或等待通知来实现。
    2. 使用IDirectSoundBuffer8::Lock锁定缓冲区的一部分。这个方法返回一个或两个地址,从该地址数据能够被立刻写入。
    3. 使用标准内存拷贝程序将音频数据写入返回的地址中。
    4. 使用IDirectSoundBuffer8::Unlock为缓冲区解锁。
    IDirectSoundBuffer8::Lock可能返回两个地址的原因是你能够锁定多达缓冲区大小的任意字节数,而忽略起始点。例如,假设你在一个40 000字节缓冲区的20 000字节处开始锁定30 000字节。这时你必须进行两次独立内存拷贝。

    虽然可以锁定整个缓冲区,但是在缓冲区播放时你不能这么做。通常你每次只更新缓冲区的一小部分。例如,在播放指针到达缓冲区的四分之二时,你能够锁定缓冲区的四分之一部分并写入数据。你永远不能对位于播放指针和写指针之间的缓冲区部分进行写操作。

    下面的函数向一个声音缓冲区写数据,起始位置由dwOffset传入:

    BOOL AppWriteDataToBuffer( 
        LPDIRECTSOUNDBUFFER8 lpDsb,  
    // The buffer.
        DWORD dwOffset,              // Our own write cursor.
        LPBYTE lpbSoundData,         // Start of our data.
        DWORD dwSoundBytes)          // Size of block to copy.

      LPVOID  lpvPtr1; 
      DWORD dwBytes1; 
      LPVOID  lpvPtr2; 
      DWORD dwBytes2; 
      HRESULT hr; 
     
      
    // Obtain memory address of write block. This will be in two parts
      
    // if the block wraps around.
     
      hr 
    = lpDsb->Lock(dwOffset, dwSoundBytes, &lpvPtr1, 
          
    &dwBytes1, &lpvPtr2, &dwBytes2, 0); 
     
      
    // If the buffer was lost, restore and retry lock. 
     
      
    if (DSERR_BUFFERLOST == hr) 
      

        lpDsb
    ->Restore(); 
        hr 
    = lpDsb->Lock(dwOffset, dwSoundBytes, 
            
    &lpvPtr1, &dwBytes1,
            
    &lpvPtr2, &dwBytes2, 0); 
      }
     
      
    if (SUCCEEDED(hr)) 
      

        
    // Write to pointers. 
     
        CopyMemory(lpvPtr1, lpbSoundData, dwBytes1); 
        
    if (NULL != lpvPtr2) 
        

          CopyMemory(lpvPtr2, lpbSoundData
    +dwBytes1, dwBytes2); 
        }
     
     
        
    // Release the data back to DirectSound. 
     
        hr 
    = lpDsb->Unlock(lpvPtr1, dwBytes1, lpvPtr2, 
        dwBytes2); 
        
    if (SUCCEEDED(hr)) 
        

          
    // Success. 
          return TRUE; 
        }
     
      }
     
     
      
    // Lock, Unlock, or Restore failed. 
     
      
    return FALSE; 
    }

  • 相关阅读:
    小结 编程练习 制作新按钮,“新窗口打开网站” ,新窗口打开时弹出确认框,是否打开,通过输入对话框,打开的窗口要求,宽400像素,高500像素,无菜单栏、无工具栏。
    关闭窗口(window.close)
    打开新窗口(window.open) open() 方法可以查找一个已经存在或者新建的浏览器窗口。 语法: window.open([URL], [窗口名称], [参数字符串])
    提问(prompt 消息对话框)用于询问一些需要与用户交互的信息。弹出消息对话框(包含一个确定按钮、取消按钮与一个文本输入框)
    确认(confirm 消息对话框)语法:confirm(str); 消息对话框通常用于允许用户做选择的动作,如:“你对吗?”等。弹出对话框(包括一个确定按钮和一个取消按钮)
    警告(alert 消息对话框) 如果你不点击“确定”,就不能对网页做任何操作,这个小窗口就是使用alert实现的
    Socket的3次握手链接与4次断开握手
    大型电子商务网站架构之--分布式可扩展数据库架构
    程序员成长历程的四个阶段
    盘点 Github 所用到的开源项目
  • 原文地址:https://www.cnblogs.com/top5/p/1635052.html
Copyright © 2020-2023  润新知