当前位置: 首页 > news >正文

Windows软件插件-写wav

下载本插件
本插件,将PCM音频流写入WAV音频文件。或将PCM音频流压缩为ALAW格式,写入WAV文件。可以创作大文件(超过4字节所能表示的大小)。插件类型为DLL,可以在win32和MFC程序中使用。使用本插件创建的ALAW格式WAV音频文件,Windows播放器不能播放,可以使用其它播放器播放。

使用方法

首先,加载本“写wav”DLL,获得DLL模块句柄。

	HMODULE hWav = LoadLibrary(L"写wav.dll");//加载“写wav”DLL模块

获取所有导出函数的地址。

typedef int(__cdecl *MYPROC_VOID)();
typedef int(__cdecl *MYPROC_WAV_Init)(int index, WAV_INIT init);
typedef int(__cdecl *MYPROC_ISample)(int index, BYTE* pB, LONG len);
typedef int(__cdecl *MYPROC_IVOID)(int index);MYPROC_VOID WAV_Create=NULL;
MYPROC_WAV_Init WAV_Init=NULL;
MYPROC_ISample WAV_Sample=NULL;
MYPROC_IVOID WAV_Run=NULL;
MYPROC_IVOID WAV_Stop=NULL;
MYPROC_IVOID WAV_Exit=NULL;
MYPROC_IVOID WAV_GetState=NULL;
MYPROC_VOID WAV_DestroyAll=NULL;if (hWav){WAV_Create=(MYPROC_VOID)GetProcAddress(hWav, "Create");//获取“创建写wav类对象”函数地址WAV_Init=(MYPROC_WAV_Init)GetProcAddress(hWav, "Init");//获取“初始化”函数地址WAV_Sample = (MYPROC_ISample)GetProcAddress(hWav, "WriteSample");//获取“写样本”函数地址WAV_Run=(MYPROC_IVOID)GetProcAddress(hWav, "Run");//“运行”函数WAV_Stop = (MYPROC_IVOID)GetProcAddress(hWav, "Stop");//“停止”函数WAV_Exit = (MYPROC_IVOID)GetProcAddress(hWav, "Exit");//“退出”函数WAV_GetState = (MYPROC_IVOID)GetProcAddress(hWav, "GetState");//“获取状态”函数WAV_DestroyAll=(MYPROC_VOID)GetProcAddress(hWav, "DestroyAll");//“销毁所有类对象”函数}

调用“创建”函数,创建一个写wav类对象。对象在DLL内部,外部无法直接访问。

		WAV_Create(); //创建写wav类对象。可以多次调用该函数,以创建多个对象;函数返回对象索引,索引从0开始

提供初始化参数,调用“初始化”函数。初始化函数创建了写wav线程。在线程中,创建wav文件,写wav文件头,格式块。

struct WAV_INIT//“初始化参数”结构
{WCHAR* Path;//输出文件路径int FormatType;//压缩方式。仅支持PCM(值1),ALAW(值6)WORD nChannels;//声道数DWORD SamplesPerSec;//音频采样率
};WAV_INIT WavInit;WavInit.Path = L"D:\\某名称.wav";//提供wav输出文件路径WavInit.FormatType = 1;//PCMWavInit.nChannels = 2;//2声道WavInit.SamplesPerSec = 48000;//采样率48000WAV_Init(0, WavInit);//参数1为“写wav类对象”索引。如果只创建了一个对象,使用索引0初始化该对象,如果有第二个对象,使用索引1

调用“运行”函数。函数调用后,可以写入样本。

		WAV_Run(0);//参数0,表示运行第一个类对象

反复调用“写样本”函数,写入样本。函数的参数1为类对象索引;参数2,提供包含wav数据的样本缓冲区指针;参数3,样本的字节大小。

		WAV_Sample(0, pB, len);//写wav样本。pB类型为BYTE*,len类型为LONG

调用“停止”函数,可以暂停写入样本。即使此时“写样本”函数仍在调用,也不会将样本写入wav文件。

		WAV_Stop(0);//参数0,表示暂停第一个类对象

调用“停止”和“退出”函数。结束写样本,完善wav文件,包括指定文件大小,数据大小。退出写wav线程。

		WAV_Stop(0);WAV_Exit(0);

在程序退出时,销毁写wav对象。

		WAV_DestroyAll();//函数可以销毁创建的所有对象

“写wav”DLL的全部代码

创建DLL时,需指定“在共享DLL中使用MFC”。
WavWriter.h

#pragma once
#include <SDKDDKVer.h>#define WIN32_LEAN_AND_MEAN             // 从 Windows 头中排除极少使用的资料
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS      // 某些 CString 构造函数将是显式的
#define _AFX_NO_MFC_CONTROLS_IN_DIALOGS         // 移除对话框中的 MFC 控件支持#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN            // 从 Windows 头中排除极少使用的资料
#endif#include <afx.h>
#include <afxwin.h>         // MFC 核心组件和标准组件
#include <afxext.h>         // MFC 扩展
#ifndef _AFX_NO_OLE_SUPPORT
#include <afxdtctl.h>           // MFC 对 Internet Explorer 4 公共控件的支持
#endif
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>                     // MFC 对 Windows 公共控件的支持
#endif // _AFX_NO_AFXCMN_SUPPORT// Windows 头文件: 
#include <windows.h>struct WAV_INIT 
{WCHAR* Path;//输出文件路径int FormatType;//压缩方式。仅支持PCM(值1),ALAW(值6)WORD nChannels;//声道数DWORD SamplesPerSec;//音频采样率
};class CQueue//队列
{
public:CQueue(UINT size, HANDLE hExit);~CQueue();BOOL Add(BYTE* pB, LONG len);BOOL Reduce(BYTE*& pB, LONG& len);UINT mSize;BYTE* pBuffer = NULL;BYTE* pAdd = NULL, *pReduce = NULL;HANDLE hAdd = NULL;HANDLE hReduce = NULL;HANDLE mhExit = NULL;
};class WavWriter
{
public:WavWriter();~WavWriter();WAV_INIT mInit;//初始化结构对象HANDLE hStop = NULL;//“停止”事件句柄HANDLE hExit = NULL;//“退出”事件句柄HANDLE hThread = NULL;//线程句柄HANDLE hReady = NULL;CQueue* pQueue = NULL;//样本队列BOOL mRun = FALSE;void Run();void Stop();void Exit();CString WavFilePath;//wav输出文件路径BOOL Init(WAV_INIT init);//初始化函数void WriteSample(BYTE* pB, LONG len){DWORD dw = WaitForSingleObject(hStop, 0);//检测“停止”信号if (dw == WAIT_OBJECT_0)//如果“停止”有信号,不将样本加入队列return;if (pQueue)pQueue->Add(pB, len);}
};

WavWriter.cpp

#include "WavWriter.h"CQueue::CQueue(UINT size, HANDLE hExit)
{mSize = size;mhExit = hExit;pBuffer = new BYTE[size * 10];pAdd = pReduce = pBuffer;hAdd = CreateSemaphore(NULL, 0, 10, NULL);//创建“已用”信号量,初始计数0,最大计数10hReduce = CreateSemaphore(NULL, 10, 10, NULL);//创建“可用”信号量,初始计数10,最大计数10
}
CQueue::~CQueue()
{delete[] pBuffer; pBuffer = NULL;CloseHandle(hAdd); CloseHandle(hReduce);
}BOOL CQueue::Add(BYTE* pB, LONG len)
{HANDLE h[2] = { hReduce, mhExit };DWORD dw = WaitForMultipleObjects(2, h, FALSE, INFINITE);//“可用”信号量减1,无限期等待if (dw == 1)return FALSE;//如果有“退出”信号,返回。消除阻塞CopyMemory(pAdd, &len, 4); pAdd += 4;CopyMemory(pAdd, pB, len); pAdd += mSize - 4;if (pAdd > pBuffer + mSize * 9)pAdd = pBuffer;LONG Pre;ReleaseSemaphore(hAdd, 1, &Pre);//“已用”信号量加1return TRUE;
}BOOL CQueue::Reduce(BYTE*& pB, LONG& len)
{HANDLE h[2] = { hAdd, mhExit };DWORD dw = WaitForMultipleObjects(2, h, FALSE, INFINITE);//“已用”信号量减1,无限期等待if (dw == 1)return FALSE;//如果有“退出”信号,返回。消除阻塞CopyMemory(&len, pReduce, 4); pReduce += 4;CopyMemory(pB, pReduce, len); pReduce += mSize - 4;if (pReduce > pBuffer + mSize * 9)pReduce = pBuffer;LONG Pre;ReleaseSemaphore(hReduce, 1, &Pre);//“可用”信号量加1return TRUE;
}WavWriter::WavWriter()
{hStop = CreateEvent(NULL, TRUE, TRUE, NULL);hExit = CreateEvent(NULL, TRUE, FALSE, NULL);hReady = CreateEvent(NULL, FALSE, FALSE, NULL);//创建“线程初始化完成”事件,自动重置,初始无信号
}WavWriter::~WavWriter()
{CloseHandle(hReady); CloseHandle(hStop); CloseHandle(hExit);
}unsigned char linear2alaw(int pcm_val);DWORD WINAPI WriterThread(LPVOID lp)
{WavWriter* pWriter = (WavWriter*)lp;pWriter->pQueue = new CQueue(1000000 + 4, pWriter->hExit);CFile F;F.Open(pWriter->WavFilePath, CFile::modeCreate | CFile::modeWrite);F.Write("RF64", 4);DWORD FileSize = UINT32_MAX;F.Write(&FileSize, 4);F.Write("WAVE", 4);F.Write("ds64", 4);DWORD ds64Size = 28;F.Write(&ds64Size, 4);//ds64块大小ULONGLONG dsFileSizePos = F.GetPosition();//记录文件大小位置ULONGLONG dsFileSize = 0;//此时并非实际大小F.Write(&dsFileSize, 8); //文件大小 = 文件总大小 - 8ULONGLONG dsDataSize = 0;//此时并非实际大小F.Write(&dsDataSize, 8);//数据大小ULONGLONG tableSize = 0;F.Write(&tableSize, 8);DWORD xw = 0;F.Write(&xw, 4);//保留F.Write("fmt ", 4);//fmtDWORD fmtSize = 16;F.Write(&fmtSize, 4);//fmt块大小WORD Format;Format = (WORD)pWriter->mInit.FormatType;F.Write(&Format, 2);//音频格式WORD nch = pWriter->mInit.nChannels;F.Write(&nch, 2);//声道数DWORD nSamples = pWriter->mInit.SamplesPerSec;F.Write(&nSamples, 4);//采样率 DWORD nBytes;if (pWriter->mInit.FormatType == 6)//ALAW{nBytes = nSamples * nch;}else//PCM{nBytes = nSamples * nch * 2;}F.Write(&nBytes, 4);//传输率 WORD block;if (pWriter->mInit.FormatType == 6){block = nch;}else//PCM{block = nch * 2;}F.Write(&block, 2);//块对齐  WORD bits;if (pWriter->mInit.FormatType == 6){bits = 8;}else{bits = 16;}F.Write(&bits, 2);//样本位数F.Write("data", 4);//写数据块标识DWORD DataSize = UINT32_MAX;F.Write(&DataSize, 4);ULONGLONG DataStar = F.GetPosition();BYTE* pS = new BYTE[1000000]; LONG len;BYTE* pD = NULL;if (pWriter->mInit.FormatType == 6){pD = new BYTE[500000];}SetEvent(pWriter->hReady);//发送“线程初始化完成”信号Agan:DWORD mStop = WaitForSingleObject(pWriter->hStop, 0);if (mStop != WAIT_OBJECT_0)//如果“停止”无信号{BOOL BReduce = pWriter->pQueue->Reduce(pS, len);//从队列读取样本if (BReduce)//如果读取样本成功{if (pWriter->mInit.FormatType == 6){short sh; BYTE data;for (int i = 0; i < len / 2; i++)//将PCM音频数据转换为ALAW数据{CopyMemory(&sh, pS + i * 2, 2);data = linear2alaw(sh);CopyMemory(pD + i, &data, 1);}F.Write(pD, len / 2);}else//PCM{F.Write(pS, len);}}}DWORD mExit = WaitForSingleObject(pWriter->hExit, 0);if (mExit == WAIT_OBJECT_0)//有“退出”信号{dsDataSize = F.GetPosition() - DataStar;dsFileSize = F.GetPosition() - 8;F.Seek(dsFileSizePos, CFile::begin);//移动文件指针到“文件大小”位置F.Write(&dsFileSize, 8);//写文件大小F.Write(&dsDataSize, 8);//写数据大小tableSize = dsDataSize / block;F.Write(&tableSize, 8);F.Close();Sleep(200);delete[] pS; if(pD)delete[] pD;delete pWriter->pQueue;return 0;}goto Agan;
}BOOL WavWriter::Init(WAV_INIT init)
{DWORD dw = WaitForSingleObject(hThread, 0);if (dw == WAIT_TIMEOUT)return FALSE;//如果线程已存在,返回if (init.FormatType != 1 && init.FormatType != 6){MessageBox(NULL, L"只允许PCM(1)和ALAW(6)", L"写WAV", MB_OK); return FALSE;}mInit = init;WavFilePath = (CString)init.Path;//wav输出文件路径ResetEvent(hExit);//设置“退出”无信号SetEvent(hStop);//设置“停止”有信号ResetEvent(hReady); //设置“线程初始化完成”无信号hThread = CreateThread(NULL, 0, WriterThread, this, 0, NULL);WaitForSingleObject(hReady, INFINITE);//等待“初始化完成”信号mRun = TRUE;return TRUE;
}void WavWriter::Run()
{ResetEvent(hStop);//设置“停止”无信号
}void WavWriter::Stop()
{SetEvent(hStop);//设置“停止”有信号
}void WavWriter::Exit()
{mRun = FALSE;SetEvent(hStop);//设置“停止”有信号SetEvent(hExit);//设置“退出”有信号WaitForSingleObject(hThread, INFINITE);//等待线程退出
}#define QUANT_MASK  (0xf)        
#define SEG_SHIFT   (4)       static short seg_end[8] = { 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF };unsigned char _u2a[128] = {1,  1,  2,  2,  3,  3,  4,  4,5,  5,  6,  6,  7,  7,  8,  8,9,  10, 11, 12, 13, 14, 15, 16,17, 18, 19, 20, 21, 22, 23, 24,25, 27, 29, 31, 33, 34, 35, 36,37, 38, 39, 40, 41, 42, 43, 44,46, 48, 49, 50, 51, 52, 53, 54,55, 56, 57, 58, 59, 60, 61, 62,64, 65, 66, 67, 68, 69, 70, 71,72, 73, 74, 75, 76, 77, 78, 79,81, 82, 83, 84, 85, 86, 87, 88,89, 90, 91, 92, 93, 94, 95, 96,97, 98, 99, 100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128
};unsigned char _a2u[128] = {1,  3,  5,  7,  9,  11, 13, 15,16, 17, 18, 19, 20, 21, 22, 23,24, 25, 26, 27, 28, 29, 30, 31,32, 32, 33, 33, 34, 34, 35, 35,36, 37, 38, 39, 40, 41, 42, 43,44, 45, 46, 47, 48, 48, 49, 49,50, 51, 52, 53, 54, 55, 56, 57,58, 59, 60, 61, 62, 63, 64, 64,65, 66, 67, 68, 69, 70, 71, 72,73, 74, 75, 76, 77, 78, 79, 79,80, 81, 82, 83, 84, 85, 86, 87,88, 89, 90, 91, 92, 93, 94, 95,96, 97, 98, 99, 100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127
};static int search(int val, short *table, int size)
{int     i;for (i = 0; i < size; i++) {if (val <= *table++)return (i);}return (size);
}unsigned char linear2alaw(int pcm_val)
{int             mask;int             seg;unsigned char   aval;if (pcm_val >= 0){mask = 0xD5;}else{mask = 0x55;pcm_val = -pcm_val - 1;}seg = search(pcm_val, seg_end, 8);if (seg >= 8)return (0x7F ^ mask);else{aval = seg << SEG_SHIFT;if (seg < 2)aval |= (pcm_val >> 4) & QUANT_MASK;elseaval |= (pcm_val >> (seg + 3)) & QUANT_MASK;return (aval ^ mask);}
}WavWriter* pWavWriter[10];//类对象指针数组
int mNu = -1;#ifdef __cplusplus    // If used by C++ code, 
extern "C" {          // we need to export the C interface
#endif__declspec(dllexport) int __cdecl Create()//创建类对象{mNu++;if (mNu > 9)return -1;//最多创建10个类对象pWavWriter[mNu] = new WavWriter();return mNu;}__declspec(dllexport) int __cdecl Init(int index, WAV_INIT WavInit)//初始化指定对象{if (pWavWriter[index]->Init(WavInit))return 1;return 0;}__declspec(dllexport) int __cdecl WriteSample(int index, BYTE* pB, LONG len)//指定对象写样本{pWavWriter[index]->WriteSample(pB, len);return 0;}__declspec(dllexport) int __cdecl GetState(int index)//获取指定对象状态{return (int)pWavWriter[index]->mRun;}__declspec(dllexport) int __cdecl Run(int index)//运行指定对象{pWavWriter[index]->Run();return 0;}__declspec(dllexport) int __cdecl Stop(int index)//停止指定对象{pWavWriter[index]->Stop();return 0;}__declspec(dllexport) int __cdecl Exit(int index)//退出指定对象{pWavWriter[index]->Exit();return 0;}__declspec(dllexport) int __cdecl DestroyAll()//销毁所有对象{for (int i = 0; i <= mNu; i++){delete pWavWriter[i];}return 0;}#ifdef __cplusplus
}
#endif
http://www.xdnf.cn/news/451351.html

相关文章:

  • 【Embedding Models】嵌入模型选择指南
  • 蓝卓入选2025宁波最具潜力新品牌TOP10
  • 数据库字段唯一性修复指南:从设计缺陷到规范实现
  • 安装windows版本的nacos
  • 总结下Jackson 中的JsonNode,ObjectNode,ArrayNode的方法
  • 时代推动建筑管理变革,楼宇自控系统成现代建筑管理必由之路
  • 数据结构·字典树
  • 每周靶点:TREM2、DLL3及文献分享
  • 代码随想录算法训练营第60期第三十六天打卡
  • W1电力线载波通信技术
  • Linux 常用命令 -hostnamectl【主机名控制】
  • Mixup
  • 【RabbitMQ】发布确认机制的具体实现
  • 3Dblox
  • 【Python3教程】Python3基础篇之输入与输出
  • 车载网关--- 职责边界划分与功能解耦设计
  • 安卓基础(Bitmap)
  • 致远OA项目管理应用包简介【附百度网盘链接】
  • scratch基础-外观模块
  • 基于EFISH-SCB-RK3576/SAIL-RK3576的智能安检机技术方案‌
  • 基于SpringBoot+Vue的房屋租赁管理系统源码包(完整版)开发实战
  • matlab提取脑电数据的五种频域特征指标数值
  • 电脑软件出现应用程序未响应
  • JJJ:linux ida
  • 深入掌握 Python 切片操作:解锁数据处理的高效密码
  • hadoop知识点
  • Guix System 系统详解:从架构到生态的深度解析
  • WebGL图形编程实战【7】:变换流水线 × 坐标系与矩阵精讲
  • 【ESP32-S3】Guru Meditation Error 崩溃分析实战:使用 addr2line 工具 + bat 脚本自动解析 Backtrace
  • Blender 入门教程(二):纹理绘制