VC中使用低级音频函数WaveX播放声音文件

【VS开发】【智能语音处理】VS中声音的采集实现 vc中声音的采集是用api函数来实现的。   一、数字音频基础知识  Fourier级数:  任何周期的波形可以分解成多个正弦波,这些正弦波的频率都是整数倍。级数中其他正线波的频率是基础频率的整数倍。基础频率称为一级谐波。  PCM:  pulse code modulation,脉冲编码调制,即对波形按照固定周期频率采样。为了保证采样后数据质量,采样频率必须是样本声音 阅读详情

VC中使用低级音频函数WaveX播放声音文件


                                                     王结太  2004.08.08


---------------------------------------------------------------------------------------------------------------------


文章摘要:
  本文讨论并实现了在VC++中使用低级音频函数WaveX播放声音文件的方法。


---------------------------------------------------------------------------------------------------------------------


    Windows通过高级音频函数、媒体控制接口MCI设备驱动程序;低级音频函数MIDI Mapper、低级音频设备驱动;以及DirectSound提供了音频服务,可以从声卡获取音频流。


1. 播放声音文件的其它方法
   在介绍wavex系列之前,我先来介绍之外的其它几种方法:


1.1 MCI方法简介
   
    用MCI方法是很方便的,它对媒体设备控制主要通过命令接口函数mciSendCommand()或者字符串接口函数mciSendString()来完成的,这两个函数的作用相同。命令接口函数比命令字符串使用起来要复杂,但它为MCI提供了更为强大的控制能力,两个接口函数的原型:
MCIERROR mciSendCommand(MCIDEVICEID IDDevice,UINT uMsg,DWORD fdwCommand,DWORD dwParam);
MCIERROR mciSendString(LPCTSTR lpszCommand, LPTSTR lpszReturnString, UINT cchReturn, HANDLE hwndCallback);
比如要使用mciSendCommand方法,我们先在MCI_OPEN_PARMS中设置要播放的文件并发送MCI_OPEN命令打开声音设备,发送MCI_PLAY命令消息播放,结束后发送MCI_STOP命令关闭设备。关于它们的具体使用方法可以参考MSDN。


1.2 PlaySound方法
   
    BOOL sndPlaySound(LPCSTR lpszSound, UINT fuSound );
    BOOL PlaySound(LPCSTR pszSound,HMODULE hmod, DWORD fdwSound);
    其中参数lpszSound是需要播放声音的.WAV文件的路径和文件名,hmod在这里为NULL,fuSound是播放声音的标志,详细说明请参考VC++中的帮助。 例如播放C:/sound/music.wav可以用sndPlaySound ("c://sound//music.wav",SND_ASYNC);或PlaySound("c://sound//music.wav",NULL, SND_ASYNC|SND_NODEFAULT );如果没有找到music.wav文件,第一种格式将播放系统默认的声音,第二种格式不会播放系统默认的声音[1],这是SND_NODEFAULT标志的作用。
    当然我们也可以将声音文件作为用户自定义资源加入程序资源文件中,经过编译连接生成EXE文件,这样就可以实现无.WAV文件的声音播放。利用上面的函数也很简单,如下,其中IDR_YOUR_WAVE是加入的wave文件资源标识符:
    PlaySound(MAKEINTRESOURCE(IDR_YOUR_WAVE),GetModuleHandle(NULL), SND_RESOURCE);


2. 使用低级音频函数WaveX
   
    下面将进入文章的主题。


2.1 概述


    低层音频服务及重要的数据结构低级音频服务控制着不同的音频设备,这些设备包括WAVE、MIDI和辅助音频设备[2]。低级音频服务包括如下内容:(1)查询音频设备;(2)打开和关闭设备驱动程序;(3)分配和准备音频数据块;(4)管理音频数据块;(5)应用MMTIME结构;(6)处理错误。
   
2.2 重要消息及数据结构
   
    使用低级音频函数之所以能够对各个声音数据块操作,要归功于Windows的消息映射,Windows在采集、播放完一个数据块之后就会发送有关的消息。播放声音涉及到的重要消息及触发条件如下:
    MM_WOM_CLOSE:在一个波形声音输出设备关闭时发出,之后该设备句柄不再有效
    MM_WOM_DONE:当给定的输出缓存播放完毕返回给应用程序,或者直接调用waveOutReset函数停止播放并重置管理器
    MM_WOM_OPEN:当给定的波形声音输出设备被打开时
   
    MOM_CLOSE:当MIDI输出设备关闭时
    WOM_DONE:当留缓冲播放完毕并正被返回程序时发到MIDI输出回调函数
    WOM_OPEN:当MIDI输出设备打开时


    重要的数据结构:
    波形数据格式 WAVEFORMAT/WAVEFORMATEX
    波形数据缓冲区格式 WAVEHDR
    音频输出设备性能 WAVEOUTCAPS
   
    这些内容都定义在mmsystem.h头文件中,更为具体的信息请参阅MSDN。
   
2.3 wavex播放声音波形文件方法的大致流程


    常用mmio函数:
    mmioOpen( ) 打开一个RIFF文件
    mmioDescend ( ) 进入块
    mmioRead( ); 该取RIFF文件
    mmioAscend ( ); 跳出块
    mmioClose( ); 关闭PIFF文件
    对于块来说,进入块和跳出块是配对的。


    读取WAV文件的读取过程:
    mmioOpen( ) 打开文件
    ↓
    mmioDescend ("WAVE") 进入"fmt"块
    ↓
    mmioRead( ) 读取WAVE文件格式信息
    ↓
    mmioAscend ( ) 跳出"fmt"块
    ↓ 
    mmioDescend ("data") 进入"data"块
    ↓
    mmioRead( ) 读取WAVE数据信息
    ↓
    mmioClose( ) 关闭文件。 
   
    输出WAV文件的过程:
    WaveOutOpen () 打开一个输出设备
    ↓
    WaveOutPrepareHeader() 准备WAVE数据头。 
    ↓ 
    WaveOutWrite() 将数据写入设备并开始播放 
    ↓ 
    WaveOutReset() 停止播放并重置管理器 
    ↓ 
    WaveOutClose() 并闭播放设备 
    ↓ 
    WaveOutUnpareHeader() 清理用WaveOutPrepareHeader准备的Wave 
   
2.4 主要程序清单


2.4.1 播放部分


void CPlayWaveDlg::OnPlay()
{
 LPSTR szFileName;//声音文件名
 LPSTR szPathName;
 MMCKINFO mmckinfoParent;
 MMCKINFO mmckinfoSubChunk;
 DWORD dwFmtSize;
 DWORD m_WaveLong; 
 WAVEFORMATEX* lpFormat;
 DWORD m_dwDataOffset;
 DWORD m_dwDataSize; 
 WAVEOUTCAPS pwoc; 
 LONG lSoundOffset;
 LONG lSoundLong;



 CEdit* pEdit = (CEdit*) GetDlgItem(IDC_FILE);
 pEdit->GetWindowText(m_strFileName);
 
 if (m_strFileName == "")
 {
  ShowMsg("Please select a wave file to play!");
  return;
 }


 szPathName = m_strPathName.GetBuffer(0);
 szFileName = m_strFileName.GetBuffer(0);


 //打开波形文件
 if (!(m_hmmio = mmioOpen(szPathName, NULL, MMIO_READ | MMIO_ALLOCBUF)))
 {
  /*-------------------------------------------------------------------------------
  信息显示函数ShowMsg():
  void CPlayWaveDlg::ShowMsg(char* szMsg, ...)
  {
   va_list vl;
   char szBuf[256];
  
   va_start(vl, szMsg);
   vsprintf(szBuf, szMsg, vl);
   va_end(vl);
  
   ::MessageBox(NULL, szBuf, "WavePlayer", MB_OK | MB_ICONEXCLAMATION);
  }
  ---------------------------------------------------------------------------------*/
  ShowMsg("Failed to open file: %s", szFileName);
  return;
 }


 //进入块,检查打开文件是否是wave文件
 mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
 if (mmioDescend(m_hmmio, (LPMMCKINFO) & mmckinfoParent, NULL,
   MMIO_FINDRIFF))
 {
  ShowMsg("%s is an invalid wave file!", szFileName);
  mmioClose(m_hmmio, NULL);
  return;
 }


 //寻找 'fmt' 块
 mmckinfoSubChunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
 if (mmioDescend(m_hmmio, &mmckinfoSubChunk, &mmckinfoParent,
   MMIO_FINDCHUNK))
 {
  ShowMsg("Cannot find fmt chunk in %s!", szFileName);
  mmioClose(m_hmmio, NULL);
  return;
 }


 //获得 'fmt '块的大小,申请内存
 dwFmtSize = mmckinfoSubChunk.cksize ;
 m_hFormat = LocalAlloc(LMEM_MOVEABLE, LOWORD(dwFmtSize));
 if (!m_hFormat)
 {
  ShowMsg("Alloc memory failed!");
  return;
 }


 lpFormat = (WAVEFORMATEX *) LocalLock(m_hFormat);
 if (!lpFormat)
 {
  ShowMsg("Lock memory failed!");
  OnStop();
  return;
 }


 if ((unsigned long) mmioRead(m_hmmio, (HPSTR) lpFormat, dwFmtSize) !=
  dwFmtSize)
 {
  ShowMsg("Read format chunk of %s failed!", szFileName);
  OnStop();
  return;
 }
 //离开 fmt 块
 mmioAscend(m_hmmio, &mmckinfoSubChunk, 0);
 //寻找 'data' 块
 mmckinfoSubChunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
 if (mmioDescend(m_hmmio, &mmckinfoSubChunk, &mmckinfoParent,
   MMIO_FINDCHUNK))
 {
  ShowMsg("Cannot find data chunk in: %s", szFileName);
  OnStop();
  return;
 }
 //获得 'data'块的大小
 m_dwDataSize = mmckinfoSubChunk.cksize ;
 m_dwDataOffset = mmckinfoSubChunk.dwDataOffset ;
 if (m_dwDataSize == 0L)
 {
  ShowMsg("%s has no data!", szFileName);
  OnStop();
  return;
 }


 //为音频数据分配内存
 lpData = new char[m_dwDataSize];
 if (!lpData)
 {
  ShowMsg("Alloc memory for wave data failed!");
  OnStop();
  return;
 }


 lSoundOffset = m_dwDataOffset;
 LONG lSize = mmioSeek(m_hmmio, lSoundOffset, SEEK_SET);
 if (lSize < 0)
 {
  ShowMsg("Seek data chunk of %s failed!", szFileName);
  OnStop();
  return;
 }
 lSoundLong = m_dwDataSize;
 m_WaveLong = mmioRead(m_hmmio, lpData, lSoundLong);
 if (m_WaveLong < 0)
 {
  ShowMsg("Read data chunk of %s failed!", szFileName);
  OnStop();
  return;
 }
 //检查音频设备,返回音频输出设备的性能
 if (waveOutGetDevCaps(WAVE_MAPPER, &pwoc, sizeof(WAVEOUTCAPS)) != 0)
 {
  ShowMsg("waveOutGetDevCaps() failed!");
  OnStop();
  return;
 }
 
 //检查音频输出设备是否能播放指定的音频文件
 /*----------------------------------------------------------------------------------------------
 waveOutOpen函数最后三个参数的设置对消息处理方式起决定性作用,需要特别注意,通常我们用下列处理方法:
 1. 使用窗口作为消息的接收者,则第四个参数设置为该窗口的句柄,则和这次播放有关的消息都将进入该窗口的消息队列,这时           第五个参数为NULL,第六个参数为CALLBACK_WINDOW,表明由窗口的过程来处理消息。
 2. 直接使用回调函数来处理消息,则第四个参数设置为该回调函数的指针,则和这次播放有关的消息都将由该函数处理,这时第           五个参数为传入该函数的参数,第六个参数为CALLBACK_FUNCTION,表明由指定函数来处理消息。
 3. 使用新的线程来处理消息,则第四个参数设置为该线程函数的指针,和这次播放有关的消息都将由该线程处理,这时第五个参           数为传入该函数的参数,第六个参数为CALLBACK_THREAD,表明由线程来处理消息。
 4. 如果你不需要处理消息,这后面三个参数分别为NULL,NULL,CALLBACK_NULL
 ----------------------------------------------------------------------------------------------*/
 if (waveOutOpen(&hWaveOut, WAVE_MAPPER, lpFormat, (ULONG)m_hWnd, NULL, CALLBACK_WINDOW) !=
  0)
 {
  ShowMsg("Open the wave out devices failed!");
  OnStop();
  return;
 }


 //准备待播放的数据
 pWaveOutHdr.lpData = (HPSTR) lpData;
 pWaveOutHdr.dwBufferLength = m_WaveLong;
 pWaveOutHdr.dwFlags = 0;
 pWaveOutHdr.dwLoops = 5;
 if (waveOutPrepareHeader(hWaveOut, &pWaveOutHdr, sizeof(WAVEHDR)) != 0)
 {
  ShowMsg("Failed to prepare the wave data buffer!");
  OnStop();
 }
 //将数据写入设备并开始播放
 if (waveOutWrite(hWaveOut, &pWaveOutHdr, sizeof(WAVEHDR)) != 0)
 {
  ShowMsg("Failed to write the wave data buffer");
  OnStop();
 }
}


2.4.2 停止播放部分


void CPlayWaveDlg::OnStop()
{
 if (m_hmmio != NULL)
 {
  mmioClose(m_hmmio, NULL);
 }
 //停止播放并重置管理器
 waveOutReset(hWaveOut);
 //关闭播放设备
 waveOutClose(hWaveOut);
 //清理用WaveOutPrepareHeader准备的Wave。
 waveOutUnprepareHeader(hWaveOut, &pWaveOutHdr, sizeof(WAVEHDR));


 //释放内存
 if (m_hFormat != NULL)
 {
  LocalUnlock(m_hFormat);
  m_hFormat = NULL;
 }
 
 if (m_hFormat != NULL)
 {
  LocalFree(m_hFormat);
  m_hFormat = NULL;
 }
 if (lpData != NULL)
 {
  delete[] lpData;
  lpData = NULL;
 } 
}


2.4.3 处理消息部分:


添加消息映射:ON_MESSAGE(MM_WOM_DONE,OnMMWomDone)


void CPlayWaveDlg::OnMMWomDone(UINT wParam, LONG lParam)
{
// ShowMsg("Play finished!");
 OnStop();
}


2.4.4 相关头文件


/*-----------------------------------------------------------------------------------------------------------------------
说明:本文介绍的操作函数的声明包含在mmsystem.h头文件中,因此在程序中必须用#include "mmsystem.h"语句加入头文件。同时在编译时要加入动态连接导入库winmm.lib,具体实现方法有两种:
1. 从Developer Studio的Project菜单中选择Settings,然后在Link选项卡上的Object/Library Modules控制中加入winmm.lib
2. 如下所示在代码中加入#pragma comment(lib, "winmm.lib")
-----------------------------------------------------------------------------------------------------------------------*/
#include "mmsystem.h"
#pragma comment(lib, "winmm.lib")


class CPlayWaveDlg : public CDialog
{


//省略与播放无关部分
//................


protected:


 HANDLE m_hData;
 HWAVEOUT hWaveOut;
 WAVEHDR pWaveOutHdr;
 HANDLE m_hFormat;
 HPSTR lpData;//音频数据
 HMMIO m_hmmio;//音频文件句柄


 CString m_strPathName;
 CString m_strFileName;


 void ShowMsg(char *szMsg, ...);


 afx_msg void OnPlay();
 afx_msg void OnStop();
 
 afx_msg void OnMMWomDone(UINT wParam, LONG lParam);
 DECLARE_MESSAGE_MAP()
};


以上代码在Visual C++ 6.0 + windows 2000 pro 上通过。


3. 应用
   
    低级音频函数能够具体的在内存中对各个声音数据块进行细节控制,比如可以通过检测声音的振幅强度进行声音采集的筛选,或者进行声音文件的剪切合并等,这就为声音文件的灵活操作提供了很好的方法;因为它能够操作声音数据块,从而也能为声音的实时传输提供有效的途径。
   
参考文献:
1. 李灿伟 VC++中播放声音的方法
2. 李博轩 Visuanl C++ 6.0多媒体开发指南。北京:清华大学出版社,2000年2月.71-75 
 

C++ 播放音频流(PCM裸流) 这份代码是打开PCM裸流文件并截取一段数据然后播放的,可以轻松的经过加一条线程的方式改成网络传输的形式。 立即下载

相关推荐

c++ 下利用waveOutWrite(directsound)编写的双缓冲区音频播放程序

c++ 下利用waveOutWrite(directsound)编写的双缓冲区音频播放程序 ,语音流畅,可以修改为网络音频数据的播放。(音频数据利用soket接收即可)

VC中用低级音频函数WaveX播放声音

Windows通过高级音频函数、媒体控制接口MCI设备驱动程序;低级音频函数MIDI Mapper、低级音频设备驱动;以及DirectSound提供了音频服务,可以从声卡获取音频流。1. 播放声音文件的其它方法  在介绍wavex系列之前,我先来介绍之外的其它几种方法:  1.1 MCI方法简介  用MCI方法是很方便的,它对媒体设备控制主要通过命令接口函数mciSendCommand()

seawt的专栏 1288

C语言关于使用waveout接口在Windows下的简易音乐播放界面

项目内包括了一个简易的命令行音乐播放界面以及几首wav格式的音乐,当然,也是可以播放音乐的。 功能:通过命令行播放界面,可以选择播放音乐或者将不同位深的音乐转换成16位位深输出。 1.音乐播放界面可以选择自己想放的歌(目前只内置了四首),同时根据按键提升进行不同的操作,例如控制音量、切歌等。 2.位深转换界面则比较简单,就是选择目标歌曲进行转化。 适合人群:学习waveOUT接口或者想做一个简易音乐播放界面的初学者 能学到什么:哈,那肯定是我这段事件从零开始学到的一切了 总结:由于在网上看了太多雷同甚至可以说一模一样的waveout接口使用教学,感觉想学的话资料太少且晦涩难懂,完全无从下手(对我来讲),就决定学完也发点学习成果和大家交流学习,希望自己的代码能帮到别人吧。不过不得不说,代码写的的确有点过于繁杂臃肿了,特别是线程和输入判断那块,本想将判断全部移入线程,但是线程本身必须要判断的就已经够多了,且还得用全局变量区传递信息,结果最后不知道该如何去修改很多可以精简或者合并的地方,可惜要去做别的代码内容了,这一块什么时候能想起来再改改看吧,至少应该不算是什么搬运的随便机翻的劣质教学吧。

VC++中播放声音的方法

其中参数lpszSound是需要播放声音的.WAV文件的路径和文件名, hmod在这里为NULL,fuSound是播放声音的标志,详细说明请参考VC++中的帮助。说明:1)以上使用的音频设备和声音文件操作函数的声明包含在mmsystem.h头文件中,因此在程序中必须用#include "mmsystem.h"语句加入头文件。要实现作为资源的声音文件的播放,首先要在资源管理器中加入待播放的声音文件(实现过程并不复杂,这里不在叙述)。在VC++中可以根据不同的应用要求,用不同的方法实现声音的播放。

智光工作室 1898

激光雷达与相机融合(四)----基于激光雷达与相机的碰撞检测

在这一部分,基于前面的各个部分内容,将利用激光雷达和相机实现目标的检测分类及单目标跟踪,并对车辆前方的车辆目标计算相应的碰撞时间TTC。计算方法分别利用相机和雷达实现。 1.系统的总体架构: 2.TTC计算 简单介绍一下通过激光雷达和相机计算碰撞时间的原理: 利用激光雷达点计算碰撞时间:首先根据检测框聚类出前车目标的点,并过滤掉这些点中的离群点,然后找出这些点中相对于本车最近的点,基于前后两帧以及数据采集频率就可以求解出相对速度,然后用当前帧的距离除以速度得出当前的TTC。但该方法对最近点的选取稳定性不是

张飞飞的博客 3987

SGO基线解算软件(南方测绘UI设计最美观的一款新版)

不多说,先放地址: 下载地址:https://www.southgnss.com/download_view.asp?did=361 SGO是南方测绘集团广州南方卫星导航仪器有限公司自主研发新一代南方地理数据处理平台软件,对南方特有数据格式文件(STH格式文件)、标准数据格式文件(RINEX格式文件)进行静态数据处理、动态数据后处理和进行RTK结果检验,新增加了北斗数据处理和摄影测量模块,并围绕南方的不同类型测量产品集成多款测绘领域所需的小工具,实现测绘内业数据处理一体化。 相关概念 G..

heirenqiaoke的博客 1万+

波形音频(WAVE)底层接口的学习与使用

如果想编写一个功能较强大的音频处理程序,那就必须使用低级音频函数和多媒体文件I/O来控制音频设备的输入和输出。 因为低级音频函数可直接与音频驱动程序交互,通过窗口消息或回调(CALLBACK)函数来管理音频数据块的记录和播放,控制非常灵活。

gongluck93的博客 1万+

AHB2eflash 控制器设计笔记

① SRAM② DRAM③ SSD④ SATA⑤ U 盘⑥ 移动硬盘⑦ 机械磁盘eflash。

weixin_46220498的博客 3078

vc 播放声音文件

Windows通过高级音频函数、媒体控制接口MCI设备驱动程序;低级音频函数MIDI Mapper、低级音频设备驱动;以及DirectSound提供了音频服务,可以从声卡获取音频流。1. 播放声音文件的其它方法在介绍wavex系列之前,我先来介绍之外的其它几种方法:1.1 MCI方法简介用MCI方法是很方便的,它对媒体设备控制主要通过命令接口函数mciSendComma

湛蓝的天空下有一道美丽的影子 2918

GEOS-Chem笔记——模式下载安装+驱动数据+运行流程

看过我博客的会发现我写了很多CESM的笔记,但是说实话,平时科研我其实更多时候是GEOS-Chemuser。之所以写了很多CESM笔记,其实是因为不会,就边学边写。然后GEOS-Chem已经用比较熟了,所以也没想过做笔记啥的。但是我发现越来越多朋友私信我各种CESM问题,我觉得我可能给大家营造了一种我是CESM达人的错觉。感觉自己有点跑偏了呢。公平起见,我觉得我有必要补充点GEOS-Chem笔记。 GEOS-Chem是研究大气化学的人常用的大气化学传输模式,在全世界范围的大气化学研究组中被广泛使用。不过.

砍柴姑娘Jourosy的博客 1万+

反应动力学仿真软件:ChemkinPro_(11).敏感性分析

敏感性分析是化学反应动力学仿真中的一项重要技术,通过对模型参数的变化对模型输出的影响进行评估,可以帮助研究人员优化模型、验证实验数据和评估不确定性。ChemkinPro 提供了强大的敏感性分析功能,可以方便地进行参数选择、仿真设置和结果解读。通过实际案例研究,我们可以看到敏感性分析在燃烧、催化和环境化学等领域的广泛应用,为科学研究和工程应用提供了有力支持。

kkchenjj的博客 1310

VC音频函数的介绍-附实例

Windows通过高级音频函数、媒体控制接口MCI设备驱动程序;低级音频函数MIDI Mapper、低级音频设备驱动;以及DirectSound提供了音频服务,可以从声卡获取音频流。   1. 播放声音文件的其它方法   在介绍wavex系列之前,我先来介绍之

程序员成长之路 1213

YOLOv8/v9轻量化优化:剪枝30%+蒸馏提精,模型体积缩至4MB还能跑Jetson

剪枝:用敏感度分析找到“可牺牲的30%”,不碰核心特征;蒸馏:借大模型的“经验”补回精度,甚至反超原始小模型;量化:针对边缘设备特性优化量化策略,把体积和延迟压到最低。如果你的项目卡在边缘部署(速度慢/体积大),按“剪枝→蒸馏→量化”三步走,90%能在Jetson上跑通30FPS+的实时检测。需要轻量化模型文件(v8s/v9s剪枝蒸馏后权重)、剪枝工具和Jetson部署脚本的,评论区扣“轻量化”,直接发你可运行版本~

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 669

(转载)基于Visual C++6.0的声音文件操作

 一、前言  当前Visual C++相关的编程资料中,无论是大部头的参考书,还是一些计算机杂志,对声音文件的处理都是泛泛的涉及一下,许多编程爱好者都感到对该部分的内容了解不是很透彻,本文希望能够给刚刚涉及到声音处理领域的朋友们起到一个引路的作用,帮助他们尽快进入声音处理的更深奥空间。  当前计算机系统处理声音文件有两种办法:一是使用现成的软件,如微软的录音机、SoundForge、CoolEdi

清闲老窝的专栏 1245

STM32Cube高效开发教程<高级篇><FreeRTOS>(十八)-----软件定时器

一、 软件定时器概述声明:本人水平有限,博客可能存在部分错误的地方,请广大读者谅解并向本人反馈错误。本专栏博客参考《STM32Cube高效开发教程(高级篇)》,有意向的读者可以购买正版书籍辅助学习,本书籍由王维波老师、鄢志丹老师、王钊老师倾力打造,书籍内容干货满满。在FreeRTOS中,自动创建的任务有空闲任务和定时器服务任务。FreeRTOS可以通过定时器服务任务提供软件定时器功能。在某些对定时精度要求不太高,无须使用硬件定时器的情况下,我们可以使用FreeRTOS的软件定时器。

我的博客 157

问题解答:如何不通过修改底层数据库表的方式,给数据库对应的数据结构,增添新的字段?

现在需要将这张表里的内容读取到 ABAP 内表里,并且针对每个行项目,增加一个新的列字段,我随便举个例子,这个列字段名称叫 LENGTH,值为 OBJ_NAME 字段的长度,使用。最笨的办法就是下面这样定义一个新的类型,这个类型的每个字段名称,都来自数据库表 TADIR 的同名字段,在末尾再增添自定义字段 length.其实我们是做 ALV 输出,只需要 ABAP 内表变量的类型,包含 TADIR 数据库表的全部字段,再加上新的 LENGTH 字段即可。这相当于多了一个中间层,没办法直接被 ALV 处理。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 487

waveOutReset 停止播放并重置管理器

原则:(1) waveOutReset不是立即返回的函数, 而需要等待驻留在WAVEDEV里的音频BUFFER全部标记为WOM_DONE,经过callback proc处理完毕后, waveOutReset才会返回. (2) 在waveOutReset调用到返回之间的这段时间内, 禁止任何线程对处于reset中的HWAVEOUT调用任何WAVE API, 否则立刻造成死锁.把握住这两个

Lisa的专栏 2020

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

学习笔记-C语言关于waveout接口的使用(终?)

项目内包括了一个简易的命令行音乐播放界面以及几首wav格式的音乐,当然,也是可以播放音乐的。 功能:通过命令行播放界面,可以选择播放音乐或者将不同位深的音乐转换成16位位深输出。 1.音乐播放界面可以选择自己想放的歌(目前只内置了四首),同时根据按键提升进行不同的操作,例如控制音量、切歌等。 2.位深转换界面则比较简单,就是选择目标歌曲进行转化。 适合人群:学习waveOUT接口或者想做一个简易音乐播放界面的初学者 能学到什么:哈,那肯定是我这段事件从零开始学到的一切了

weixin_65851880的博客 1457

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

使用WaveOut接口播放WAV文件

我需要在插件中实现一边接收数据,一边展示媒体文件的功能,因此从最简单的音频文件来开始研究,绝大多数API如:playSound等都是根据完整文件来播放音频的,即便是内存模式也是需要将整个文件全部读入一片内容,然后将内存指针传递给playSound。最后逐渐寻找到WaveOut接口。 要一边接收数据一边播放,首先需要得到头信息,然后使用多个缓存在WaveOutWrite中交替为音频设备填充数据。

JumuFENG's blog 1万+

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

上一篇: 发些c/c++/vc/驱动/网络安全的好书和资料
下一篇: Getting the Preferred Audio Device Number
普通网友
博客等级 码龄22年 1万+粉丝 3156原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值