菜鸟问各位大侠:如何将几个声音文件并成一个文件?救救我!!!

NewSea 2000-08-22 10:35:00
如何使用Delphi将几个声音文件(Wav格式)合并成一个文件?救救我!!!
...全文
171 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
NewSea 2000-11-08
  • 打赏
  • 举报
回复
ok
jiangtao 2000-08-23
  • 打赏
  • 举报
回复
这是我写的一个程序,实现合并标准wav文件还是比较简单的
jiangtao 2000-08-23
  • 打赏
  • 举报
回复
unit waveutil;

interface

uses
Windows,Sysutils,MMSystem,Dialogs;

const
Wave_Format_ADPCM = 2;
MSADPCM_NUM_COEF = 7; { ADPCM: number of predictors }

FOURCC_RIFF = $46464952; { 'RIFF' }
FOURCC_WAVE = $45564157; { 'WAVE' }
FOURCC_fmt = $20746D66; { ' fmt' }
FOURCC_data = $61746164; { 'data' }

type

ArrayIndex = 0..99999999;
TByteArray = array[ArrayIndex] of Byte;
PByteArray = ^TByteArray;
TSmallintArray = array[ArrayIndex] of Smallint;
PSmallintArray = ^TSmallintArray;

WaveFileHeader = packed record
ckid: FOURCC; // chunk ID--'RIFF'
cksize: DWORD; // chunk size--File SIze
rifftype: FOURCC; // riff type --'WAVE'
end;

RawWaveData = packed record
chunkID: FOURCC; // fmt chunk id-'DATA'
chunkSize: LongInt; //
//waveformData: array[0..0] of byte;
end;

WaveFmtHeader =packed record
fmtid: FOURCC; // fmt chunk id-'fmt '
chunkSize: LongInt; // size of the chunk not include <id and size>
end;

PWaveFormatE = ^TWaveFormat;
TWaveFormatE = packed record
wFormatTag: Word; //format type-- PCM = 1
nChannels: Word; // number of channels (i.e. mono, stereo, etc.)
nSamplesPerSec: DWORD; // sample rate (11025,22050,44010)
nAvgBytesPerSec: DWORD; // for buffer estimation
nBlockAlign: Word; // block size of data
wBitsPerSample: Word; // number of bits per sample of mono data
//cbSize: Word; // the count in bytes of the size of extra
//extra data format
end;

{ Predictors for ADPCM }
TADPCMCoef = packed record
Coef1, Coef2: SmallInt;
end;
TADPCMCoefSet = Array[0..MSADPCM_NUM_COEF-1] of TADPCMCoef;
PADPCMCoefSet = ^TADPCMCoefSet;

TWaveFormatEx = packed record
wFormatTag: Word; { format type }
nChannels: Word; { number of channels (i.e. mono, stereo, etc.) }
nSamplesPerSec: Longint; { sample rate }
nAvgBytesPerSec: Longint; { for buffer estimation }
nBlockAlign: Word; { block size of data }
wBitsPerSample: Word;
cbSize: Word; { SizeOf(wSamplesPerBlock..Predictors. Optional with PCM
extra size}
wSamplesPerBlock: SmallInt;
wNumCoef: SmallInt; { const 7 }
CoefSet: TADPCMCoefSet;
end;
PWaveFormatEx = ^TWaveFormatEx;

TWaveFile = Class (TObject)
FMMioHandle :Integer;
FFileName :String;
FWaveFormat : TWaveFormatEx;
FDataBytes,FDataOffset: Integer;
FFileSize:Integer;
SampleCount: LongInt;
public
constructor Create;
destructor Destory;
function OpenWaveFile(FileName: string):Boolean;
function GetDataBuffer(Buffer:PChar):Integer;
function ReadData(Buffer:PChar;dataPos,readbytes:Integer):Integer;
function WriteData(Buffer:PChar;dataPos,readbytes:Integer):Integer;
procedure CloseWaveFile;
function GetDataSecs:Integer;
function IsFileOpen:Boolean;
published
property WaveFormat: TWaveFormatEx read FWaveFormat;
property FileSize:Integer read FFileSize;
property DataBytes:Integer read FDataBytes;
property DataSecs:Integer read GetDataSecs;
end;

function CreateWaveFile(FileName:String;SampleRate,BitsNum:Integer;Stereo:Boolean):Integer;
function PlayWaveFile(FileName:String):Integer;
function StripeWaveFile(FileName:String):Integer;
function writeWaveFileFromBuf(tmpBuffer:PChar;VocLen:Integer;TripSilence:Boolean):String;

//Used for 变换语音文件放大因子,由于输入Microphone声音太小或太大可以
//按比例进行放缩
function getBufferPeak(ptrBuf:PSmallInt;BufSize,FrameSize:Integer):Single;

function getWaveFileLen(fileName:String;var lSecs,lBytes:Integer):Bool;
function getWaveFileFormat(fileName:String;var Sample,BitsNum:Integer;var Stereo:Boolean):Bool;

implementation

Uses
{#IFDEF DETECT_VER}
Detect,
{#ENDIF}
Myutils;

function getWaveFileLen(fileName:String;var lSecs,lBytes:Integer):Bool;
begin
result:=False;
with TWaveFile.Create do
begin
if OpenWaveFile(fileName) then
begin
lSecs:=DataSecs;
lBytes:=DataBytes;
CloseWaveFile;
result:=True;
end;
Free;
end; // with

end;

function getWaveFileFormat(fileName:String;var Sample,BitsNum:Integer;var Stereo:Boolean):Bool;
begin
result:=False;
with TWaveFile.Create do
begin
if OpenWaveFile(fileName) then
begin
Sample:=FWaveFormat.nSamplesPerSec;
BitsNum:=FWaveFormat.wBitsPerSample;
if FWaveFormat.nChannels = 1 then
Stereo:=False
else
Stereo:=True;
CloseWaveFile;
result:=True;
end;
Free;
end; // with

end;


function PlayWaveFile(FileName:String):Integer;
begin
SndPlaySound(PChar(FileName),SND_SYNC or SND_NODEFAULT);
end;

procedure Error(Text: string);
var
StackTop: record end;
Stack: record
EBP: Integer;
ReturnAddress: Pointer;
end absolute StackTop;
begin
raise Exception.Create(Text) at Stack.ReturnAddress;
end;



constructor TWaveFile.Create;
begin
inherited Create;
FMMioHandle:=0;
FDataBytes:=0;
FDataOffset:=0;
FFileSize:=0;
end;

destructor TWaveFile.Destory;
begin
inherited;
if FMMioHandle <> 0 then
CloseWaveFile;
end;

//打开Wave文件,得到Wave的数据格式FWaveFormat
function TWaveFile.OpenWaveFile(FileName: string):Boolean;
var
ckRIFF, ck: TMMCKINFO;
procedure ErrExit(Msg: String);
begin
Error(FileName+': '+Msg);
end;
begin
result:=False;

if (FileName = '') or not FileExists(FileName)
then Error('File '+FileName+' not found.');

Assert(FMMioHandle=0);
FMMioHandle := mmioOpen(PChar(FileName), nil, MMIO_READ or MMIO_ALLOCBUF);
if FMMioHandle = 0 then ErrExit('mmioOpen failed');
try
FFileName:=FileName;
ckRIFF.fccType := mmioStringToFourCC('WAVE',0);
if mmioDescend(FMMioHandle, @ckRIFF, nil, MMIO_FINDRIFF) <> 0
then ErrExit('WAVE chunk not found');

FillChar(FWaveFormat,SizeOf(FWaveFormat), 0);
SampleCount := 0;

while mmioDescend(FMMioHandle, @ck, @ckRIFF, 0) = MMSYSERR_NOERROR do
begin
if (ck.dwDataOffset + ck.cksize) > (ckRIFF.dwDataOffset + ckRIFF.cksize)
then ErrExit('Chunk size mismatch');

if ck.ckid = mmioStringToFourCC('fmt ',0) then
begin
if FWaveFormat.wFormatTag = 0 then
begin
if ck.ckSize > SizeOf(TWaveFormatEx) then
ErrExit('ADPCM, unexpected number of coefficients');

if mmioRead(FMMioHandle, @FWaveFormat, ck.ckSize) <> ck.ckSize then
ErrExit('Error reading ''fmt '' chunk');
end;
end
else
if ck.ckid = mmioStringToFourCC('fact',0) then
begin
if (SampleCount = 0) and (FWaveFormat.wFormatTag = Wave_Format_ADPCM) then
begin
mmioRead(FMMioHandle, @SampleCount, SizeOf(LongInt));
end; { else multiple fact chunks - ignore }
end
else if ck.ckid = mmioStringToFourCC('data',0) then
begin
FDataBytes := ck.cksize;
case FWaveFormat.wFormatTag of
0:
ErrExit('No ''fmt '' chunk');
Wave_Format_PCM:
with FWaveFormat do
{ not documented: Avg div SamplesPerSec always integer }
SampleCount := FDataBytes div (nAvgBytesPerSec div nSamplesPerSec);
Wave_Format_ADPCM:
;
else
ErrExit('''fmt '' chunk exists, but unknown format');
end;
FDataOffset:=mmioSeek(FMmioHandle,0,1);//from cur
{
if bReadBuffer then
begin
GetMem(Buf, DataBytes);
mmioRead(FMMioHandle, PChar(Buf), DataBytes);
end;
}
end;
{ else leave subchunk }
mmioAscend(FMMioHandle, @ck, 0);
end; { while mmioDescend }
finally
//mmioClose(FMMioHandle,0);
FFileSize:=mmioSeek(FMMioHandle,0,2);
end;
result:=True;
end;

//返回Wave数据的总秒数
function TWaveFile.GetDataSecs:Integer;
begin
result:=DataBytes div FWaveFormat.nAvgBytesPerSec;
end;

//读出整个Wave数据区
function TWaveFile.GetDataBuffer(Buffer:PChar):Integer;
begin
result:=0;
if (FDataBytes > 0) and (FDataOffset>=44) then
begin
mmioSeek(FMMioHandle,FDataoffset,0);//from beginning
result:=mmioRead(FMmioHandle,Buffer,FDataBytes);
end;
end;



function TWaveFile.WriteData(Buffer:PChar;dataPos,readbytes:Integer):Integer;
begin
if FMMiohandle <> 0 then
begin
mmioSeek(FMMioHandle,FDataOffset+dataPos,0);
result:=mmioWrite(FMMioHandle,buffer,readBytes);
//可能有错
//应重新修改FWaveFormat的相关数据
end;
end;

function TWaveFile.ReadData(Buffer:PChar;dataPos,readbytes:Integer):Integer;
begin
if FMMiohandle <> 0 then
begin
mmioSeek(FMMioHandle,FDataOffset+dataPos,0);
result:=mmioRead(FMMioHandle,buffer,readBytes);
end;
end;


procedure TWaveFile.CloseWaveFile;
begin
if FMMioHandle <> 0 then
mmioClose(FMMioHandle,0);
FMMioHandle:=0;
end;

function TWaveFile.IsFileOpen:Boolean;
begin
result := (FMMioHandle <> 0);
end;


//功能:创建Wave文件
//参数:FileName-----文件名
//返回:其他:成功
// -1: 错误
function CreateWaveFile(FileName:String;SampleRate,BitsNum:Integer;Stereo:Boolean):Integer;
var
aHDr :WaveFileHeader;
aData :RawWaveData;
aFmt : WaveFmtHeader;
aWaveFormat:TWaveFormatEx;
begin
result:=FileCreate(FileName);
if result = -1 then
//ShowMessage('Create File Error');
Error('无法创建文件');
if result > 0 then
begin
with aHdr do
begin
ckid:=FOURCC_RIFF;
cksize:=44;
rifftype:=FOURCC_WAVE;
end;
FileWrite(result,aHDr,SizeOf(WaveFileHeader));

with aFmt do
begin
fmtid:=FOURCC_FMT;
chunksize:=$10; //for standard format
end;
FileWrite(result,aFmt,SizeOf(WaveFmtHeader));

with aWaveFormat do
begin
aWaveFormat.wFormatTag:=1; //pcm
{
aWaveFormat.nChannels:=1;
aWaveFormat.nSamplesPerSec:=11025;
aWaveFormat.wBitsPerSample:=16;
aWaveFormat.nAvgBytesPerSec:=22050;
}
if Stereo then
aWaveFormat.nChannels:=2
else
aWaveFormat.nChannels:=1;

aWaveFormat.nSamplesPerSec:=SampleRate;
aWaveFormat.wBitsPerSample:=BitsNum;
aWaveFormat.nBlockAlign:=(BitsNum div 8)*aWaveFormat.nChannels;
aWaveFormat.nAvgBytesPerSec:=SampleRate*aWaveFormat.nBlockAlign;
end;
FileWrite(result,aWaveFormat,SizeOf(TWaveFormatE));

with aData do
begin
chunkID:=FOURCC_DATA;
chunkSize:=0;
end;
FileWrite(result,aData,SizeOf(RawWaveData));
end;
end;
yinfudan 2000-08-23
  • 打赏
  • 举报
回复
非常困难,你得知道Wave文件的格式,然后手工读写文件完成。
我有Wave文件的格式,若要可以问我要,yinfudan@yahoo.com
alin 2000-08-23
  • 打赏
  • 举报
回复
想做什么?
可以用读二进制文件方法,
1.建新文件NEW.WAV
2.读第一个文件,写入NEW.WAV,记录长度(可在NEW.WAV前加文件头记录,如果是直接播放,即合并多个WAV的话,就不能用文件头了,WAV文件好像步接后可直接用,没什么影响的)
3.读第二个文件,在NEW.WAV后写入
4.第三个文件.,在NEW.WAV后写入......
5.关闭NEW.WAV
前导课程:      《Java工程师系列课程》前4部 课程内容:           本课程是《Java工程师系列课程》的第8部分,深入讲解Java文件和IO流的相关知识。以下是本课程的内容展示:课程共69个小节,分为三个大部分:分别是文件部分、流部分和实战项目部分。文件部分,就是左上角用红框框起来的这一部分,主要讲解对文件以及文件夹的操作,第二部分就是课程最重要的部分,也是占课程比例最大的流部分,所谓流就是用来读写数据的类。本课程用45小节的时间为学员详细讲解各种流的使用方法以及注意事项。第三部分是实战项目部分,就是右下角用蓝色方框框起来的部分,在这一部分中,将为大家讲解如何用swing技术配合课程中学习的IO流去完成一个记事本项目。实际上,除了课程最后的这记事本项目,课程中还穿插了一些规模比较小的实战项目,比如分割文件、合并文件、给文件加密这样的小项目,以及压缩和解压文件项目。课程特点:1、讲解详细:不仅仅详细讲解了文件和流的各种用法,还讲解了很多使用过程中需要注意的细节。2、干货足量:每一个小节的时长基本都超过了20分钟,能让学员学到很多知识。3、深入解决实际题:视频课程不仅讲解理论知识,还深入解决了很多实际题,例如:讲解如何通过程序判断一个文件的编码格式、如何设置文件读写权限等4、讲解经典算法:例如讲解缓冲区的管理机制,能让学员学到前辈们的精华思想5、理论结合实践:课程在文件压缩和解压、文件分割以及合并、文件加密,这些小节都配有对应的实战项目,最后还有一个规模比较大的记事本项目6、手写代码:全程手写代码完成项目预期效果:      认真学习完本课程,学员可以深入掌握Java语言操作和管理磁盘文件的技术以及通过流读写数据的技术,实实在在提高实战水平,完成从菜鸟到高手的华丽转变。

5,388

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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