㈠ 谁做过这种.wav文件的读取程序vc++或者matlab,c
function [y,Fs,bits,opt_ck] = wavread(file,ext)
nargchk(1,2,nargin);
if nargin<2, ext=[]; end % Default - read all samples
exts = numel(ext); % length of extent info
if ~strncmpi(ext,'size',exts) && (exts > 2),
error('Index range must be specified as a scalar or 2-element vector.');
end
if ~ischar(ext) && exts==1,
if ext==0,
ext='size'; % synonym for size
else
ext=[1 ext]; % Prepend start sample index
end
end
[fid,msg] = open_wav(file);
error(msg);
try
[riffck,msg] = find_cktype(fid,'RIFF');
if ~isempty(msg),
error('Not a WAVE file.');
end
msg = check_rifftype(fid,'WAVE');
error(msg);
end_of_file = 0;
opt_ck = [];
while(~end_of_file),
[ck,msg] = find_cktype(fid);
error(msg);
switch lower(ck.ID)
case 'end of file'
end_of_file = 1;
case 'fmt'
% <fmt-ck> found
[opt_ck,msg] = read_wavefmt(fid,ck,opt_ck);
error(msg);
case 'data'
% <data-ck> found:
if ~isfield(opt_ck,'fmt'),
error('Corrupt WAV file: found audio data before format information.');
end
if strncmpi(ext,'size',exts) || ...
(~isempty(ext) && all(ext==0)),
% Caller doesn't want data - just data size:
[samples,msg] = read_wavedat(ck, opt_ck.fmt, -1);
error(msg);
y = [samples opt_ck.fmt.nChannels];
else
% Read <wave-data>:
[datack,msg] = read_wavedat(ck, opt_ck.fmt, ext);
error(msg);
y = datack.Data;
end
case 'fact'
% Optional <fact-ck> found:
[opt_ck,msg] = read_factck(fid, ck, opt_ck);
error(msg);
case 'disp'
% Optional <disp-ck> found:
[opt_ck,msg] = read_dispck(fid, ck, opt_ck);
error(msg);
case 'list'
% Optional <list-ck> found:
[opt_ck, msg] = read_listck(fid, ck, opt_ck);
error(msg);
otherwise
% Skip over data in unprocessed chunks:
if rem(ck.Size,2), ck.Size=ck.Size+1; end
if(fseek(fid,ck.Size,0)==-1),
error('Incorrect chunk size information in WAV file.');
end
end
end
catch
fclose(fid);
error(lasterr);
end
fclose(fid);
% Parse structure info for return to user:
Fs = opt_ck.fmt.nSamplesPerSec;
if opt_ck.fmt.wFormatTag == 1 || opt_ck.fmt.wFormatTag == 3,
% Type 3 floating point has no nBitsPerSample field, so use
% nBlockAlign to figure out number of bits
bits = (opt_ck.fmt.nBlockAlign / opt_ck.fmt.nChannels) * 8;
else
bits = []; % Unknown
end
% end of wavread()
% ------------------------------------------------------------------------
% Local functions:
% ------------------------------------------------------------------------
% ---------------------------------------------
% OPEN_WAV: Open a WAV file for reading
% ---------------------------------------------
function [fid,msg] = open_wav(file)
% Append .wav extension if it's missing:
[pat,nam,ext] = fileparts(file);
if isempty(ext),
file = [file '.wav'];
end
[fid,msg] = fopen(file,'rb','l'); % Little-endian
if fid == -1,
msg = 'Cannot open file.';
end
return
% ---------------------------------------------
% READ_CKINFO: Reads next RIFF chunk, but not the chunk data.
% If optional sflg is set to nonzero, reads SUBchunk info instead.
% Expects an open FID pointing to first byte of chunk header.
% Returns a new chunk structure.
% ---------------------------------------------
function [ck,msg] = read_ckinfo(fid)
msg = '';
ck.fid = fid;
ck.Data = [];
err_msg = 'Truncated chunk header found - possibly not a WAV file.';
[s,cnt] = fread(fid,4,'char');
% Do not error-out if a few (<4) trailing chars are in file
% Just return quickly:
if (cnt~=4),
if feof(fid),
% End of the file (not an error)
ck.ID = 'end of file'; % unambiguous chunk ID (>4 chars)
ck.Size = 0;
else
msg = err_msg;
end
return
end
ck.ID = deblank(char(s'));
% Read chunk size (skip if subchunk):
[sz,cnt] = fread(fid,1,'uint32');
if cnt~=1,
msg = err_msg;
return
end
ck.Size = sz;
return
% ---------------------------------------------
% FIND_CKTYPE: Finds a chunk with appropriate type.
% Searches from current file position specified by fid.
% Leaves file positions to data of desired chunk.
% If optional sflg is set to nonzero, finds a SUBchunk instead.
% ---------------------------------------------
function [ck,msg] = find_cktype(fid,ftype)
msg = '';
if nargin<2, ftype = ''; end
[ck,msg] = read_ckinfo(fid);
if ~isempty(msg), return; end
% Was a required chunk type specified?
if ~isempty(ftype) & ~strcmpi(ck.ID,ftype),
msg = ['<' ftype '-ck> did not appear as expected'];
end
return
% ---------------------------------------------
% CHECK_RIFFTYPE: Finds the RIFF data type.
% Searches from current file position specified by fid.
% Leaves file positions to data of desired chunk.
% ---------------------------------------------
function msg = check_rifftype(fid,ftype)
msg = '';
[rifftype,cnt] = fread(fid,4,'char');
rifftype = char(rifftype)';
if cnt~=4,
msg = 'Not a WAVE file.';
elseif ~strcmpi(rifftype,ftype),
msg = ['File does not contain required ''' ftype ''' data chunk.'];
end
return
% ---------------------------------------------
% READ_LISTCK: Read the FLIST chunk:
% ---------------------------------------------
function [opt_ck,msg] = read_listck(fid,ck, orig_opt_ck)
opt_ck = orig_opt_ck;
orig_pos = ftell(fid);
total_bytes = ck.Size; % # bytes in subchunk
nbytes = 4; % # of required bytes in <list-ck> header
msg = '';
err_msg = 'Error reading <list-ck> chunk.';
if total_bytes < nbytes,
msg = err_msg;
return
end
% Read standard <list-ck> data:
listdata = char(fread(fid,total_bytes,'uchar')');
listtype = lower(listdata(1:4)); % Get LIST type
listdata = listdata(5:end); % Move past INFO
if strcmp(listtype,'info'),
% Information:
while(~isempty(listdata)),
id = listdata(1:4);
switch lower(id)
case 'iart'
name = 'Artist';
case 'icmt'
name = 'Comments';
case 'icrd'
name = 'Creation date';
case 'icop'
name = ['Copy' 'right'];
case 'ieng'
name = 'Engineer';
case 'inam'
name = 'Name';
case 'iprd'
name = 'Proct';
case 'isbj'
name = 'Subject';
case 'isft'
name = 'Software';
case 'isrc'
name = 'Source';
otherwise
name = id;
end
if ~isfield(opt_ck,'info'),
opt_ck.info = [];
end
len = listdata(5:8) * 2.^[0 8 16 24]';
txt = listdata(9:9+len-1);
% Fix up text: deblank, and replace CR/LR with LF
txt = deblank(txt);
idx=findstr(txt,char([13 10]));
txt(idx) = '';
% Store - don't include the "name" info
opt_ck.info.(lower(id)) = txt;
if rem(len,2), len=len+1; end
listdata = listdata(9+len:end);
end
else
if ~isfield(opt_ck,'list'),
opt_ck.list = [];
end
opt_ck.list.(listtype) = listdata;
end
% Skip over any unprocessed data:
if rem(total_bytes,2), total_bytes=total_bytes+1; end
rbytes = total_bytes - (ftell(fid) - orig_pos);
if rbytes~=0,
if (fseek(fid,rbytes,'cof')==-1),
msg = err_msg;
end
end
return
% ---------------------------------------------
% READ_DISPCK: Read the DISP chunk:
% ---------------------------------------------
function [opt_ck, msg] = read_dispck(fid,ck,orig_opt_ck)
opt_ck = orig_opt_ck;
orig_pos = ftell(fid);
total_bytes = ck.Size; % # bytes in subchunk
nbytes = 4; % # of required bytes in <disp-ck> header
msg = '';
err_msg = 'Error reading <disp-ck> chunk.';
if total_bytes < nbytes,
msg = err_msg;
return
end
% Read standard <disp-ck> data:
data = fread(fid,total_bytes,'uchar');
% Process data:
% First few entries are size info:
icon_data = data;
siz_info = reshape(icon_data(1:2*4),4,2)';
siz_info = siz_info*(2.^[0 8 16 24]');
is_icon = isequal(siz_info,[8;40]);
if ~is_icon,
% Not the icon:
opt_ck.disp.name = 'DisplayName';
txt = deblank(char(data(5:end)'));
opt_ck.disp.text = txt;
end
% Skip over any unprocessed data:
if rem(total_bytes,2), total_bytes=total_bytes+1; end
rbytes = total_bytes - (ftell(fid) - orig_pos);
if rbytes~=0,
if(fseek(fid,rbytes,'cof')==-1),
msg = err_msg;
end
end
return
% ---------------------------------------------
% READ_FACTCK: Read the FACT chunk:
% ---------------------------------------------
function [opt_ck,msg] = read_factck(fid,ck,orig_opt_ck)
opt_ck = orig_opt_ck;
orig_pos = ftell(fid);
total_bytes = ck.Size; % # bytes in subchunk
nbytes = 4; % # of required bytes in <fact-ck> header
msg = '';
err_msg = 'Error reading <fact-ck> chunk.';
if total_bytes < nbytes,
msg = err_msg;
return
end
% Read standard <fact-ck> data:
opt_ck.fact = char(fread(fid,total_bytes,'uchar')');
% Skip over any unprocessed data:
if rem(total_bytes,2), total_bytes=total_bytes+1; end
rbytes = total_bytes - (ftell(fid) - orig_pos);
if rbytes~=0,
if(fseek(fid,rbytes,'cof')==-1),
msg = err_msg;
end
end
return
% ---------------------------------------------
% READ_WAVEFMT: Read WAVE format chunk.
% Assumes fid points to the <wave-fmt> subchunk.
% Requires chunk structure to be passed, indicating
% the length of the chunk in case we don't recognize
% the format tag.
% ---------------------------------------------
function [opt_ck,msg] = read_wavefmt(fid,ck,orig_opt_ck)
opt_ck = orig_opt_ck;
orig_pos = ftell(fid);
total_bytes = ck.Size; % # bytes in subchunk
nbytes = 14; % # of required bytes in <wave-format> header
msg = '';
err_msg = 'Error reading <wave-fmt> chunk.';
if total_bytes < nbytes,
msg = err_msg;
return
end
% Read standard <wave-format> data:
opt_ck.fmt.wFormatTag = fread(fid,1,'uint16'); % Data encoding format
opt_ck.fmt.nChannels = fread(fid,1,'uint16'); % Number of channels
opt_ck.fmt.nSamplesPerSec = fread(fid,1,'uint32'); % Samples per second
opt_ck.fmt.nAvgBytesPerSec = fread(fid,1,'uint32'); % Avg transfer rate
opt_ck.fmt.nBlockAlign = fread(fid,1,'uint16'); % Block alignment
% Read format-specific info:
switch opt_ck.fmt.wFormatTag
case 1
% PCM Format:
[opt_ck.fmt, msg] = read_fmt_pcm(fid, ck, opt_ck.fmt);
end
% Skip over any unprocessed fmt-specific data:
if rem(total_bytes,2), total_bytes=total_bytes+1; end
rbytes = total_bytes - (ftell(fid) - orig_pos);
if rbytes~=0,
if(fseek(fid,rbytes,'cof')==-1),
msg = err_msg;
end
end
return
% ---------------------------------------------
% READ_FMT_PCM: Read <PCM-format-specific> info
% ---------------------------------------------
function [fmt,msg] = read_fmt_pcm(fid, ck, fmt)
% There had better be a bits/sample field:
total_bytes = ck.Size; % # bytes in subchunk
nbytes = 14; % # of bytes already read in <wave-format> header
msg = '';
err_msg = 'Error reading PCM <wave-fmt> chunk.';
if (total_bytes < nbytes+2),
msg = err_msg;
return
end
[bits,cnt] = fread(fid,1,'uint16');
nbytes=nbytes+2;
if (cnt~=1),
msg = err_msg;
return
end
fmt.nBitsPerSample=bits;
% Are there any additional fields present?
if (total_bytes > nbytes),
% See if the "cbSize" field is present. If so, grab the data:
if (total_bytes >= nbytes+2),
% we have the cbSize uint16 in the file:
[cbSize,cnt]=fread(fid,1,'uint16');
nbytes=nbytes+2;
if (cnt~=1),
msg = err_msg;
return
end
fmt.cbSize = cbSize;
end
% Simply skip any remaining stuff - we don't know what it is:
if rem(total_bytes,2), total_bytes=total_bytes+1; end
rbytes = total_bytes - nbytes;
if rbytes~=0,
if (fseek(fid,rbytes,'cof') == -1);
msg = err_msg;
end
end
end
return
% ---------------------------------------------
% READ_WAVEDAT: Read WAVE data chunk
% Assumes fid points to the wave-data chunk
% Requires <data-ck> and <wave-format> structures to be passed.
% Requires extraction range to be specified.
% Setting ext=[] forces ALL samples to be read. Otherwise,
% ext should be a 2-element vector specifying the first
% and last samples (per channel) to be extracted.
% Setting ext=-1 returns the number of samples per channel,
% skipping over the sample data.
% ---------------------------------------------
function [dat,msg] = read_wavedat(datack,wavefmt,ext)
% In case of unsupported data compression format:
dat = [];
fmt_msg = '';
switch wavefmt.wFormatTag
case 1
% PCM Format:
[dat,msg] = read_dat_pcm(datack,wavefmt,ext);
case 2
fmt_msg = 'Microsoft ADPCM';
case 3
% normalized floating-point
[dat,msg] = read_dat_pcm(datack,wavefmt,ext);
case 6
fmt_msg = 'CCITT a-law';
case 7
fmt_msg = 'CCITT mu-law';
case 17
fmt_msg = 'IMA ADPCM';
case 34
fmt_msg = 'DSP Group TrueSpeech TM';
case 49
fmt_msg = 'GSM 6.10';
case 50
fmt_msg = 'MSN Audio';
case 257
fmt_msg = 'IBM Mu-law';
case 258
fmt_msg = 'IBM A-law';
case 259
fmt_msg = 'IBM AVC Adaptive Differential';
otherwise
fmt_msg = ['Format #' num2str(wavefmt.wFormatTag)];
end
if ~isempty(fmt_msg),
msg = ['Data compression format (' fmt_msg ') is not supported.'];
end
return
% ---------------------------------------------
% READ_DAT_PCM: Read PCM format data from <wave-data> chunk.
% Assumes fid points to the wave-data chunk
% Requires <data-ck> and <wave-format> structures to be passed.
% Requires extraction range to be specified.
% Setting ext=[] forces ALL samples to be read. Otherwise,
% ext should be a 2-element vector specifying the first
% and last samples (per channel) to be extracted.
% Setting ext=-1 returns the number of samples per channel,
% skipping over the sample data.
% ---------------------------------------------
function [dat,msg] = read_dat_pcm(datack,wavefmt,ext)
dat = [];
msg = '';
% Determine # bytes/sample - format requires rounding
% to next integer number of bytes:
BytesPerSample = ceil(wavefmt.nBlockAlign / wavefmt.nChannels);
if (BytesPerSample == 1),
dtype='uchar'; % unsigned 8-bit
elseif (BytesPerSample == 2),
dtype='int16'; % signed 16-bit
elseif (BytesPerSample == 3)
dtype='bit24'; % signed 24-bit
elseif (BytesPerSample == 4),
% 32-bit 16.8 float (type 1 - 32-bit)
% 32-bit normalized floating point
dtype = 'float';
% 32-bit 24.0 float (type 1 - 24-bit)
if wavefmt.wFormatTag ~= 3 && wavefmt.nBitsPerSample == 24,
BytesPerSample = 3;
end
else
msg = 'Cannot read PCM file formats with more than 32 bits per sample.';
return
end
total_bytes = datack.Size; % # bytes in this chunk
total_samples = total_bytes / BytesPerSample;
SamplesPerChannel = total_samples / wavefmt.nChannels;
if ~isempty(ext) && isscalar(ext) && ext==-1
% Just return the samples per channel, and fseek past data:
dat = SamplesPerChannel;
% Add in a pad-byte, if required:
total_bytes = total_bytes + rem(datack.Size,2);
if(fseek(datack.fid,total_bytes,'cof')==-1),
msg = 'Error reading PCM file format.';
end
return
end
% Determine sample range to read:
if isempty(ext),
ext = [1 SamplesPerChannel]; % Return all samples
else
if numel(ext)~=2,
msg = 'Sample limit vector must have 2 elements.';
return
end
if ext(1)<1 || ext(2)>SamplesPerChannel,
msg = 'Sample limits out of range.';
return
end
if ext(1)>ext(2),
msg = 'Sample limits must be given in ascending order.';
return
end
end
bytes_remaining = total_bytes; % Preset byte counter
% Skip over leading samples:
if ext(1)>1,
% Skip over leading samples, if specified:
skipcnt = BytesPerSample * (ext(1)-1) * wavefmt.nChannels;
if(fseek(datack.fid, skipcnt,'cof') == -1),
msg = 'Error reading PCM file format.';
return
end
%
% Update count of bytes remaining:
bytes_remaining = bytes_remaining - skipcnt;
end
% Read desired data:
nSPCext = ext(2)-ext(1)+1; % # samples per channel in extraction range
dat = datack; % Copy input structure to output
% extSamples = wavefmt.nChannels*nSPCext;
dat.Data = fread(datack.fid, [wavefmt.nChannels nSPCext], dtype);
%
% Update count of bytes remaining:
skipcnt = BytesPerSample*nSPCext*wavefmt.nChannels;
bytes_remaining = bytes_remaining - skipcnt;
% if cnt~=extSamples, dat='Error reading file.'; return; end
% Skip over trailing samples:
if(fseek(datack.fid, BytesPerSample * ...
(SamplesPerChannel-ext(2))*wavefmt.nChannels, 'cof')==-1),
msg = 'Error reading PCM file format.';
return
end
% Update count of bytes remaining:
skipcnt = BytesPerSample*(SamplesPerChannel-ext(2))*wavefmt.nChannels;
bytes_remaining = bytes_remaining - skipcnt;
% Determine if a pad-byte is appended to data chunk,
% skipping over it if present:
if rem(datack.Size,2),
fseek(datack.fid, 1, 'cof');
end
% Rearrange data into a matrix with one channel per column:
dat.Data = dat.Data';
% Normalize data range: min will hit -1, max will not quite hit +1.
if BytesPerSample==1,
dat.Data = (dat.Data-128)/128; % [-1,1)
elseif BytesPerSample==2,
dat.Data = dat.Data/32768; % [-1,1)
elseif BytesPerSample==3,
dat.Data = dat.Data/(2^23); % [-1,1)
elseif BytesPerSample==4,
if wavefmt.wFormatTag ~= 3, % Type 3 32-bit is already normalized
dat.Data = dat.Data/32768; % [-1,1)
end
end
return
% end of wavread.m
㈡ 如何在C程序中调用音频文件
一.在程序中直接播放声音文件
在VC++ 中的多媒体动态连接库中提供了一组与音频设备有关的函数。利用这些函数可以方便地播放声音。最简单的播放声音方法就是直接调用VC++中提供的声音播放函数BOOL sndPlaySound ( LPCSTR lpszSound,UINT fuSound ); 或BOOL PlaySound( LPCSTR lpszSound, HMODULE hmod, DWORD fuSound );其中参数lpszSound是需要播放声音的.W***文件的路径和文件名, hmod在这里为NULL,fuSound是播放声音的标志,详细说明请参考VC++中的帮助。 例如播放C:soundmusic.wav可以用sndPlaySound ("c:\sound\music.wav",SND_ASYNC);或PlaySound("c:\sound\music.wav",NULL, SND_ASYNC|SND_NODEFAULT );如果没有找到music.wav文件,第一种格式将播放系统默认的声音,第二种格式不会播放系统默认的声音。
二.将声音文件加入到程序中
在VC++的程序设计中,可以利用各种标准的资源,如位图,菜单,对话框等。同时VC++也允许用户自定义资源,因此我们可以将声音文件作为用户自定义资源加入程序资源文件中,经过编译连接生成EXE文件,实现无.W***文件的声音播放。要实现作为资源的声音文件的播放,首先要在资源管理器中加入待播放的声音文件。
具体步骤入下:
1.获得包含资源的模块句柄:
HMODULE hmod=AfxGetResourceHandle();
2.检索资源块信息:
HRSRC hSndResource=FindResource(hmod,MAKEINTRESOURCE(IDR_W***E1),_T("W***E"));
3. 装载资源数据并加锁:
HGLOBAL hGlobalMem=LoadResource(hmod,hSndResource);
LPCTSTR lpMemSound=(LPCSTR)LockResource(hGlobalMem);
4.播放声音文件:
sndPlaySound(lpMemSound,SND_MEMORY));
5.释放资源句柄:
FreeResource(hGlobalMem);
㈢ 分析WAV音频文件
音频文件,特别是WAV格式文件,其核心由0和1的二进制数字构成。WAV文件作为微软公司开发的一种声音文件格式,遵循RIFF文件规范,广泛应用于Windows平台及其应用程序。这类文件支持多种压缩算法与音频格式,如MSADPCM、CCITT A LAW等。WAV文件的标准格式与CD一致,均采用44.1K的采样频率与16位量化数字,保证了与CD近乎相同的音质。
深入分析WAV文件结构,发现其遵循树状结构,每个块由辨识码、数据大小和数据本身组成。辨识码通常为RIFF的ASCII码,即52 49 46 46。随后的四个字节指示块大小,余下的数据则为文件内容。
在WAV格式中,除了文件头部外,还包括两个子块:fmt和data。fmt块用于描述文件信息,如采样率、数据量、编码格式和声道数等。data块则为真正播放声音的数据部分。
fmt块结构遵循RIFF模式,包含标识符“fmt”、块大小和18个字节的文件信息。fact子块有时存在,用于存储关于文件的重要信息,但并非所有标准WAV文件必备。data块是真正包含声音数据的区块。
通过对比WAV文件结构,理解其组成与功能。在数据大小的计算中,注意到由于不同计算机的存储方式差异(小端与大端),实际大小可能与预期有所不同。此外,WAVEFORMATEX结构在标准WAV文件中通常为16字节,额外的两个字节可能出现在由特定软件生成的文件中。
在C语言中,WAV文件的数据实际存储于data子块。根据文件的编码格式wFormatTag,数据存储方式各不相同。在多声道文件中,样本以交错形式存储,如8位量化时,每两个样本为一组,分别代表左声道和右声道。
具体而言,通过编程手段可从双声道WAV文件中提取单声道样本,只需每隔一个样本选取一个值即可实现。