谁有用过TAudioIO,请教如何才能把被填充到buffer中的数据存成.wav文件?

donghaiw 2003-11-10 08:38:21
不知道谁有用过这个很不错的声音控件TAudioIO,
用来对波形音频的录制和播放,还可同时显示声音的峰值,
下载地址:
http://www.csdn.net/dev/Delphi/vcl/multimedia/taudioio.zip

我的问题是:
这个控件录音时只存到buffer中,
我想把录音的数据存成wav文件,不知道怎么做啊。
希望各位帮忙。先谢了。

TAudioIO分成TAudioIn和TAudioOut,其中TAudioIn是用来录音的,
它有一个事件叫,AudioIn1BufferFilled().
这个事件在录音的过程中不停的被激活,
它是把产生的数据填入buffer中,然后产生声音峰值,
如何才能把这些buffer中的数据最终存成.wav文件呢。

具体如下:
unit TAudioInputDemo;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, AudioIO, ExtCtrls, Buttons, ComCtrls, MMSYSTEM;

type
TForm1 = class(TForm)
StartButton: TButton;
Timer1: TTimer;
StopButton: TButton;
RunStatusLabel: TLabel;
BufferStatusLabel: TLabel;
TimeStatusLabel: TLabel;
Panel1: TPanel;
RecordSpeedButton: TSpeedButton;
ProgressBar1: TProgressBar;
MaxLabel: TLabel;
AudioIn1: TAudioIn;
procedure StartButtonClick(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure AudioIn1Stop(Sender: TObject);
procedure UpdateStatus;
procedure StopButtonClick(Sender: TObject);
procedure RecordSpeedButtonClick(Sender: TObject);
function AudioIn1BufferFilled(Buffer: PChar;
var Size: Integer): Boolean;
private
{ Private declarations }
public
{ Public declarations }
Min, Max : Integer;
TempMax : Integer;
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.StartButtonClick(Sender: TObject);
begin
If (Not AudioIn1.Start(AudioIn1)) Then ShowMessage(AudioIn1.ErrorMessage)
Else
Begin
Min := 0;
Max := 0;
RecordSpeedButton.Down := TRUE;
End;
end;

function TForm1.AudioIn1BufferFilled(Buffer: PChar; var Size: Integer): Boolean;
Var
SP : ^SmallInt;
i, N, v : Integer;
xMin, xMax : Integer;

begin
N := Size Div 2;
SP := Pointer(Buffer);
xMin := SP^;
xMax := xMin;


For i := 0 to N-1 Do
Begin
v := SP^; Inc(SP);
If (xMin > v) Then xMin := v;
If (xMax < v) Then xMax := v;
End;

If (Min > xMin) Then Min := xMin;
If (Max < xMax) Then Max := xMax;

TempMax := xMax;
If (Abs(xMin) > xMax) Then TempMax := Abs(xMin);
Result := TRUE;
end;

Procedure TForm1.UpdateStatus;
begin
With AudioIn1 Do
If (AudioIn1.Active) Then
Begin
RunStatusLabel.Caption := 'Started';
BufferStatusLabel.Caption := Format('Queued: %3d; Processed: %3d',[QueuedBuffers, ProcessedBuffers]);
TimeStatusLabel.Caption := Format('Seconds %.3n',[ElapsedTime]);
End
Else
Begin
RunStatusLabel.Caption := 'Stopped';
BufferStatusLabel.Caption := '';
TimeStatusLabel.Caption := '';
End;

{ Update the progress bar }
If (AudioIn1.Active) Then
Begin
ProgressBar1.Position := Round(100*TempMax/36768.0);
If (Abs(Min) > Max) Then Max := Abs(Min);
MaxLabel.Caption := Format('Max %5d; Peak %5d',[Max,TempMax]);
End
Else
Begin
ProgressBar1.Position := 0;
MaxLabel.Caption := '';
End;

End;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
UpdateStatus;
end;

procedure TForm1.AudioIn1Stop(Sender: TObject);
begin
RecordSpeedButton.Down := FALSE;
end;


procedure TForm1.StopButtonClick(Sender: TObject);
begin
AudioIn1.StopAtOnce;
end;

procedure TForm1.RecordSpeedButtonClick(Sender: TObject);
begin
If (RecordSpeedButton.Down) Then
StartButtonClick(Sender)
Else
AudioIn1.StopAtOnce;
end;

end.
...全文
213 5 打赏 收藏 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
Haofei 2003-11-18
  • 打赏
  • 举报
回复
最好请将procedure TForm1.StartButtonClick(Sender: TObject);过程中的
WaveHeader.nChannels :=2;
WaveHeader.nSamplesPerSec := 11025;
WaveHeader.wBitsPerSample := 16;
成如下
if AudioIn1.Stereo then WaveHeader.nChannels :=2
else WaveHeader.nChannels := 1;
WaveHeader.nSamplesPerSec := AudioIn1.FrameRate;
WaveHeader.wBitsPerSample := AudioIn1.Quantization;
Haofei 2003-11-18
  • 打赏
  • 举报
回复
我帮你改了一下,在D7下通过,代码如下:
unit TAudioInputDemo;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, AudioIO, ExtCtrls, Buttons, ComCtrls, MMSYSTEM;

type
TWaveHeader = record
rId : longint; //固定标记 值为"RIFF"
rLen : longint; //随后的字节数 值为文件大小-8
wId : longint; //固定标记 值为"WAVE"
fId : longint; //ckID 值为"fmt "
fLen : longint; //nChunkSize Wave文件块的大小 16
wFormatTag : word; //音频数据的编码方式 此值常为1 表示PCM方式
nChannels : word; //声道数
nSamplesPerSec : longint; //每秒采样频率
nAvgBytesPerSec : longint; //每秒字节数
nBlockAlign : word; //一次输出的字节数 值为采样位数*声道数/8
wBitsPerSample : word; //采样位数 一般16位和8位
dId : longint; //固定标记 值为"data"
wSampleLength : longint; //采样数据长度 值为文件大小-文件头大小(44)
end;

TForm1 = class(TForm)
StartButton: TButton;
Timer1: TTimer;
StopButton: TButton;
RunStatusLabel: TLabel;
BufferStatusLabel: TLabel;
TimeStatusLabel: TLabel;
Panel1: TPanel;
RecordSpeedButton: TSpeedButton;
ProgressBar1: TProgressBar;
MaxLabel: TLabel;
AudioIn1: TAudioIn;
Label1: TLabel;
procedure StartButtonClick(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure AudioIn1Stop(Sender: TObject);
procedure UpdateStatus;
procedure StopButtonClick(Sender: TObject);
procedure RecordSpeedButtonClick(Sender: TObject);
function AudioIn1BufferFilled(Buffer: PAnsiChar;
var Size: Integer): Boolean;
private

public
{ Public declarations }
WaveHeader : TWaveHeader ;
fs : TFileStream ;
Min, Max : Integer;
TempMax : Integer;
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.StartButtonClick(Sender: TObject);
begin

fs := TFileStream.Create('d:\b.wav',fmCreate);
WaveHeader.rId := $46464952;
WaveHeader.wId := $45564157;
WaveHeader.fId := $20746d66;
WaveHeader.dId := $61746164;
WaveHeader.wFormatTag := 1 ;
WaveHeader.nChannels :=2;
WaveHeader.nSamplesPerSec := 11025;
WaveHeader.wBitsPerSample := 16;
WaveHeader.wSampleLength := 0;
WaveHeader.fLen := WaveHeader.wBitsPerSample;
WaveHeader.nAvgBytesPerSec := WaveHeader.wBitsPerSample *
WaveHeader.nSamplesPerSec *
WaveHeader.nChannels div 8;
WaveHeader.nBlockAlign := WaveHeader.wBitsPerSample*WaveHeader.nChannels div 8;
fs.Write(WaveHeader,Sizeof(WaveHeader));

If (Not AudioIn1.Start(AudioIn1)) Then ShowMessage(AudioIn1.ErrorMessage)
Else
Begin
Min := 0;
Max := 0;
RecordSpeedButton.Down := TRUE;
End;
end;

Procedure TForm1.UpdateStatus;
begin
With AudioIn1 Do
If (AudioIn1.Active) Then
Begin
RunStatusLabel.Caption := 'Started';
BufferStatusLabel.Caption := Format('Queued: %3d; Processed: %3d',[QueuedBuffers, ProcessedBuffers]);
TimeStatusLabel.Caption := Format('Seconds %.3n',[ElapsedTime]);
End
Else
Begin
RunStatusLabel.Caption := 'Stopped';
BufferStatusLabel.Caption := '';
TimeStatusLabel.Caption := '';
End;

{ Update the progress bar }
If (AudioIn1.Active) Then
Begin
ProgressBar1.Position := Round(100*TempMax/36768.0);
If (Abs(Min) > Max) Then Max := Abs(Min);
MaxLabel.Caption := Format('Max %5d; Peak %5d',[Max,TempMax]);
End
Else
Begin
ProgressBar1.Position := 0;
MaxLabel.Caption := '';
End;

End;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
UpdateStatus;
end;

procedure TForm1.AudioIn1Stop(Sender: TObject);
begin
RecordSpeedButton.Down := FALSE;
end;


procedure TForm1.StopButtonClick(Sender: TObject);
begin
AudioIn1.StopAtOnce;
WaveHeader.rLen := WaveHeader.wSampleLength+36;
fs.Seek(0,soFromBeginning);
fs.Write(WaveHeader,Sizeof(WaveHeader));
fs.Free;
end;

procedure TForm1.RecordSpeedButtonClick(Sender: TObject);
begin
If (RecordSpeedButton.Down) Then
StartButtonClick(Sender)
Else
AudioIn1.StopAtOnce;
end;

function TForm1.AudioIn1BufferFilled(Buffer: PAnsiChar;
var Size: Integer): Boolean;
Var
SP : ^SmallInt;
i, N, v : Integer;
xMin, xMax : Integer;
begin
fs.Write(buffer^,Size);
WaveHeader.wSampleLength := WaveHeader.wSampleLength + Size;
Label1.Caption := IntToStr(WaveHeader.wSampleLength);

N := Size Div 2;
SP := Pointer(Buffer);
xMin := SP^;
xMax := xMin;

For i := 0 to N-1 Do
Begin
v := SP^; Inc(SP);
If (xMin > v) Then xMin := v;
If (xMax < v) Then xMax := v;
End;

If (Min > xMin) Then Min := xMin;
If (Max < xMax) Then Max := xMax;

TempMax := xMax;
If (Abs(xMin) > xMax) Then TempMax := Abs(xMin);
Result := TRUE;
end;

end.
xiangwangz 2003-11-15
  • 打赏
  • 举报
回复
也 太长了吧 !帮你up !顶 呵呵
donghaiw 2003-11-14
  • 打赏
  • 举报
回复
怎么没有人回答?

就是声音已经存到buffer中,怎样才能从buffer中输出到wav文件中?

谢谢。
donghaiw 2003-11-11
  • 打赏
  • 举报
回复
没有人知道吗?大家快up啊
内容概要:本文围绕Module模块化开发在5G网管系统中的插件化架构应用展开,重点介绍如何通过模块化与插件化技术解决多厂商设备(如华为、中兴、爱立信等)北向接口适配难题。文章提出基于SPI机制、类加载器隔离、协议转换模块化和灰度发布等核心技术,构建可扩展、易维护的网管系统架构,并通过华为告警适配插件的完整代码示例,展示了插件从定义、加载到解析的全流程。该架构实现了厂商适配的解耦与热插拔,显著提升系统的灵活性与可维护性。; 适合人群:具备Java开发基础,熟悉SPI、类加载机制,从事通信网管系统、OSS系统或大型企业级平台开发的研发人员,尤其是工作3-5年、参与过系统集成或中间件设计的工程师; 使用场景及目标:①实现跨厂商5G基站告警采集与性能监控的统一接入;②构建可扩展的光传输网络拓扑发现与核心网配置审计系统;③支持故障诊断平台的知识插件动态扩展;④降低新增设备厂商的接入周期与运维成本; 阅读建议:此资源强调架构设计与工程实践结合,建议读者不仅关注代码实现,还需深入理解SPI机制、类加载隔离原理及插件生命周期管理策略,结合实际网管场景进行模拟开发与调试,掌握高可用插件化系统的设计要点。
内容概要:本文围绕“Module模块化开发实践项目在通信行业的应用”,系统阐述了模块化开发在嵌入式通信系统中的关键技术与实际应用。通过引入模块、接口契约和关注点分离等核心概念,结合状态机驱动、配置与代码分离、自动化测试等实践技巧,展示了如何构建高可靠、易维护的通信软件系统。文章以一个基于RTOS的多协议通信固件为例,深入分析了线路监控、协议处理与主机通信三大模块间的事件驱动机制和解耦设计,强调了硬件抽象层与消息队列在实现可移植性和可扩展性中的关键作用,并展望了算网融合、零信任安全和低代码配置等未来趋势。; 适合人群:具备嵌入式系统基础、熟悉C语言与RTOS开发,有1-3年通信或工业控制领域经验的软件工程师和技术架构师。; 使用场景及目标:①掌握通信设备中多协议栈(如Contact ID、SIA)的模块化实现方法;②学习高可用通信系统中的冗余切换、故障恢复与状态机设计;③理解如何通过模块化解耦提升系统的可测试性、可维护性和跨平台适应能力; 阅读建议:建议结合RTOS平台动手实践文中代码案例,重点关注消息队列的使用、状态机的设计以及模块间接口的定义,同时思考如何将模块化思想拓展至网络功能虚拟化与边缘计算场景。

1,184

社区成员

发帖
与我相关
我的任务
社区描述
Delphi GAME,图形处理/多媒体
社区管理员
  • GAME,图形处理/多媒体社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧