📄 mp3read.m
字号:
function [Y,FS,NBITS,OPTS] = mp3read(FILE,N,MONO,DOWNSAMP,DELAY)% MP3READ Read MP3 audio file via use of external binaries.% Y = MP3READ(FILE) reads an mp3-encoded audio file into the% vector Y just like wavread reads a wav-encoded file (one channel % per column). Extension ".mp3" is added if FILE has none.% Also accepts other formats of wavread, such as% Y = MP3READ(FILE,N) to read just the first N sample frames (N% scalar), or the frames from N(1) to N(2) if N is a two-element vector. % Y = MP3READ(FILE,FMT) or Y = mp3read(FILE,N,FMT) % with FMT as 'native' returns int16 samples instead of doubles; % FMT can be 'double' for default behavior (to exactly mirror the% syntax of wavread).%% [Y,FS,NBITS,OPTS] = MP3READ(FILE...) returns extra information:% FS is the sampling rate, NBITS is the bit depth (always 16), % OPTS.fmt is a format info string; OPTS has multiple other% fields, see WAVREAD.%% SIZ = MP3READ(FILE,'size') returns the size of the audio data contained% in the file in place of the actual audio data, returning the% 2-element vector SIZ=[samples channels].%% [Y...] = MP3READ(FILE,N,MONO,DOWNSAMP,DELAY) extends the% WAVREAD syntax to allow access to special features of the% mpg123 engine: MONO = 1 forces output to be mono (by% averaging stereo channels); DOWNSAMP = 2 or 4 downsamples by % a factor of 2 or 4 (thus FS returns as 22050 or 11025% respectively for a 44 kHz mp3 file); DELAY controls how many% "warm up" samples to drop at the start of the file; the% default value of 2257 makes an mp3write/mp3read loop for a 44% kHz mp3 file be as close as possible to being temporally% aligned; specify as 0 to prevent discard of initial samples.%% Example:% To read an mp3 file as doubles at its original width and sampling rate:% [Y,FS] = mp3read('piano.mp3');% To read the first 1 second of the same file, downsampled by a% factor of 4, cast to mono, using the default filename% extension:% [Y,FS4] = mp3read('piano', FS/4, 1, 4);%% Note: Because the mp3 format encodes samples in blocks of 26 ms (at% 44 kHz), and because of the "warm up" period of the encoder,% the file length may not be exactly what you expect.%% Note: requires external binaries mpg123 and mp3info; you% can find binaries for several platforms at:% http://labrosa.ee.columbia.edu/matlab/mp3read.html%% See also mp3write, wavread.% 2003-07-20 dpwe@ee.columbia.edu This version calls mpg123.% 2004-08-31 Fixed to read whole files correctly% 2004-09-08 Uses mp3info to get info about mp3 files too% 2004-09-18 Reports all mp3info fields in OPTS.fmt; handles MPG2LSF sizes% + added MONO, DOWNSAMP flags, changed default behavior.% 2005-09-28 Fixed bug reading full-rate stereo as 1ch (thx bjoerns@vjk.dk)% 2006-09-17 Chop off initial 2257 sample delay (for 44.1 kHz mp3)% so read-write loop doesn't get progressively delayed.% You can suppress this with a 5th argument of 0.% 2007-02-04 Added support for FMT argument to match wavread% Added automatic selection of binary etc. to allow it% to work cross-platform without editing prior to% submitting to Matlab File Exchange% find our baseline directory[path,name] = fileparts(which('mp3read'));%%%%%% Directory for temporary file (if needed)tmpdir = 'C:\mp3readwrite\tmp\';%% Try to read from environment, or use /tmp if it exists, or use CWDtmpdir = getenv('TMPDIR');if length(tmpdir) == 0 || exist(tmpdir,'file')==0 tmpdir = '/tmp';endif length(tmpdir) == 0 || exist(tmpdir,'file')==0 tmpdir = '';end% ensure it exists%if length(tmpdir) > 0 && exist(tmpdir,'file')==0% mkdir(tmpdir);%end%%%%%% Command to delete temporary file (if needed)rmcmd = 'del';%%%%%% Location of the binaries - attempt to choose automaticallympg123 = 'C:\mp3readwrite\mpg123.exe';mp3info = 'C:\mp3readwrite\mp3info.exe';%%%%%% (or edit to be hard-coded for your installation)ext = lower(computer);if strcmp(computer,'PCWIN') ext = 'exe'; rmcmd = 'del';endmpg123 = fullfile(path,['mpg123.',ext]);mp3info = fullfile(path,['mp3info.',ext]);%%%%% Process input argumentsif nargin < 2 N = 0;end% Check for FMT spec (per wavread)FMT = 'double';if ischar(N) FMT = lower(N); N = 0;endif length(N) == 1 % Specified N was upper limit N = [1 N];endif nargin < 3 forcemono = 0;else % Check for 3rd arg as FMT if ischar(MONO) FMT = lower(MONO); MONO = 0; end forcemono = (MONO ~= 0);endif nargin < 4 downsamp = 1;else downsamp = DOWNSAMP;endif downsamp ~= 1 && downsamp ~= 2 && downsamp ~= 4 error('DOWNSAMP can only be 1, 2, or 4');endif nargin < 5 mpg123delay44kHz = 2257; % empirical delay of lame/mpg123 loop delay = round(mpg123delay44kHz/downsamp);else delay = DELAY;endif strcmp(FMT,'native') == 0 && strcmp(FMT,'double') == 0 && ... strcmp(FMT,'size') == 0 error(['FMT must be ''native'' or ''double'' (or ''size''), not ''',FMT,'''']);end%%%%%% ConstantsNBITS=16;%%%%% add extension if none (like wavread)[path,file,ext] = fileparts(FILE);if isempty(ext) FILE = [FILE, '.mp3'];end%%%%%% Probe file to find format, size, etc. using "mp3info" utilitycmd = ['"',mp3info, '" -r m -p "%Q %u %r %v * %C %e %E %L %O %o %p" "', FILE,'"'];% Q = samprate, u = #frames, r = bitrate, v = mpeg version (1/2/2.5)% C = Copyright, e = emph, E = CRC, L = layer, O = orig, o = mono, p = padw = mysystem(cmd);% Break into numerical and ascii parts by finding the delimiter we put instarpos = findstr(w,'*');nums = str2num(w(1:(starpos - 2)));strs = tokenize(w((starpos+2):end));SR = nums(1);nframes = nums(2);nchans = 2 - strcmp(strs{6}, 'mono');layer = length(strs{4});bitrate = nums(3)*1000;mpgv = nums(4);% Figure samples per frame, after% http://board.mp3-tech.org/view.php3?bn=agora_mp3techorg&key=1019510889if layer == 1 smpspfrm = 384;elseif SR < 32000 && layer ==3 smpspfrm = 576; if mpgv == 1 error('SR < 32000 but mpeg version = 1'); endelse smpspfrm = 1152;endOPTS.fmt.mpgBitrate = bitrate;OPTS.fmt.mpgVersion = mpgv;% fields from wavread's OPTSOPTS.fmt.nAvgBytesPerSec = bitrate/8;OPTS.fmt.nSamplesPerSec = SR;OPTS.fmt.nChannels = nchans;OPTS.fmt.nBlockAlign = smpspfrm/SR*bitrate/8;OPTS.fmt.nBitsPerSample = NBITS;OPTS.fmt.mpgNFrames = nframes;OPTS.fmt.mpgCopyright = strs{1};OPTS.fmt.mpgEmphasis = strs{2};OPTS.fmt.mpgCRC = strs{3};OPTS.fmt.mpgLayer = strs{4};OPTS.fmt.mpgOriginal = strs{5};OPTS.fmt.mpgChanmode = strs{6};OPTS.fmt.mpgPad = strs{7};OPTS.fmt.mpgSampsPerFrame = smpspfrm;if SR == 16000 && downsamp == 4 error('mpg123 will not downsample 16 kHz files by 4 (only 2)');endif downsamp == 1 downsampstr = '';else downsampstr = [' -',num2str(downsamp)];endFS = SR/downsamp;if forcemono == 1 nchans = 1; chansstr = ' -m';else chansstr = '';end% Size-reading versionif strcmp(FMT,'size') == 1 Y = [floor(smpspfrm*nframes/downsamp), nchans];else % Temporary file to use tmpfile = fullfile(tmpdir, ['tmp',num2str(round(1000*rand(1))),'.wav']); skipx = 0; skipblks = 0; skipstr = ''; sttfrm = N(1)-1; % chop off transcoding delay? sttfrm = sttfrm + delay; % empirically measured if sttfrm > 0 skipblks = floor(sttfrm*downsamp/smpspfrm); skipx = sttfrm - (skipblks*smpspfrm/downsamp); skipstr = [' -k ', num2str(skipblks)]; end lenstr = ''; endfrm = -1; decblk = 0; if length(N) > 1 endfrm = N(2)+delay; if endfrm > sttfrm decblk = ceil(endfrm*downsamp/smpspfrm) - skipblks + 1; % we read one extra blk (+1) to cover the case where up to one bad % block is included in the part we are trying to read (it happened) lenstr = [' -n ', num2str(decblk)]; end end % Run the decode cmd=['"',mpg123,'"', downsampstr, chansstr, skipstr, lenstr, ... ' -q -w "', tmpfile,'" "',FILE,'"']; w = mysystem(cmd); % Load the data [Y,SR] = wavread(tmpfile);% % pad delay on to end, just in case% Y = [Y; zeros(delay,size(Y,2))];% % no, the saved file is just longer if decblk > 0 && length(Y) < decblk*smpspfrm/downsamp % This will happen if the selected block range includes >1 bad block disp(['Warn: requested ', num2str(decblk*smpspfrm/downsamp),' frames, returned ',num2str(length(Y))]); end % Delete tmp file mysystem([rmcmd,' "', tmpfile,'"']); % Select the desired part if endfrm > sttfrm Y = Y(skipx+(1:(endfrm-sttfrm)),:); elseif skipx > 0 Y = Y((skipx+1):end,:); end % Convert to int if format = 'native' if strcmp(FMT,'native') Y = int16((2^15)*Y); endend%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%function w = mysystem(cmd)% Run system command; report error; strip all but last line[s,w] = system(cmd);if s ~= 0 error(['unable to execute ',cmd,' (',w,')']);end% Keep just final linew = w((1+max([0,findstr(w,10)])):end);% Debug%disp([cmd,' -> ','*',w,'*']);%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%function a = tokenize(s)% Break space-separated string into cell array of strings% 2004-09-18 dpwe@ee.columbia.edua = [];p = 1;n = 1;l = length(s);nss = findstr([s(p:end),' '],' ');for ns = nss % Skip initial spaces if ns == p p = p+1; else if p <= l a{n} = s(p:(ns-1)); n = n+1; p = ns+1; end endend
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -