paulstretch_cpp

PaulStretch
Log | Files | Refs | LICENSE

MP3InputS.cpp (4766B)


      1 /*
      2   Copyright (C) 2006-2009 Nasca Octavian Paul
      3   Author: Nasca Octavian Paul
      4 
      5   This program is free software; you can redistribute it and/or modify
      6   it under the terms of version 2 of the GNU General Public License 
      7   as published by the Free Software Foundation.
      8 
      9   This program is distributed in the hope that it will be useful,
     10   but WITHOUT ANY WARRANTY; without even the implied warranty of
     11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12   GNU General Public License (version 2) for more details.
     13 
     14   You should have received a copy of the GNU General Public License (version 2)
     15   along with this program; if not, write to the Free Software Foundation,
     16   Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
     17 */
     18 
     19 #define BUFSIZE 4096 //minimum 2 buffere de mp3
     20 
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include "MP3InputS.h"
     25 using namespace std;
     26 
     27 
     28 MP3InputS::MP3InputS(){
     29 	info.nsamples=0;
     30 	info.nchannels=2;
     31 	info.samplerate=44100;
     32 	info.currentsample=0;
     33 	eof=false;
     34 	MP3_opened=false;
     35 	f=NULL;
     36 	buf=NULL;
     37 };
     38 
     39 MP3InputS::~MP3InputS(){
     40 	close();
     41 };
     42 
     43 bool MP3InputS::open(string filename){
     44 	pcm_remained=0;
     45 	close();//inchide un posibil fisier existent
     46 	eof=true;
     47 	f=fopen(filename.c_str(),"rb");
     48 	if (!f) return false;
     49 	mad_stream_init(&stream);
     50 	mad_frame_init(&frame);
     51 	mad_synth_init(&synth);
     52 
     53 	buf=new unsigned char[BUFSIZE];
     54 
     55 	MP3_opened=true;
     56 	eof=false;
     57 
     58 	fseek(f,0,SEEK_END);
     59 	info.nsamples=ftell(f);
     60 	rewind(f);
     61 	info.currentsample=0;
     62 	info.samplerate=44100;
     63 
     64 	{//find the samplerate
     65 		const int n=8192;
     66 		short int tmpsmp[n*2];
     67 		read(n,tmpsmp);//read just a sample (and ignore it) to fill info.samplerate
     68 		seek(0);
     69 		pcm_remained=0;
     70 		info.currentsample=0;
     71 		//reinit the mad
     72 		mad_synth_finish(&synth);
     73 		mad_frame_finish(&frame);
     74 		mad_stream_finish(&stream);
     75 		
     76 		mad_stream_init(&stream);
     77 		mad_frame_init(&frame);
     78 		mad_synth_init(&synth);
     79 	};
     80 
     81 	info.nchannels=2;
     82 	return true;
     83 };
     84 
     85 void MP3InputS::close(){
     86 	if (MP3_opened){
     87 		MP3_opened=false;
     88 		mad_synth_finish(&synth);
     89 		mad_frame_finish(&frame);
     90 		mad_stream_finish(&stream);
     91 		delete [] buf;
     92 		fclose(f);
     93 		f=NULL;
     94 	};
     95 };
     96 
     97 
     98 int MP3InputS::read(int nsmps,short int *smps){
     99 	int orig_nsmps=nsmps;
    100 	short int *orig_smps=smps;
    101 	if (!MP3_opened) {
    102 		eof=true;
    103 		return 0;
    104 	};
    105 	if (eof) {
    106 		for (int i=0;i<nsmps;i++) smps[i]=0;
    107 		return nsmps;
    108 	};
    109 
    110 	if (pcm_remained>0){
    111 		int nconverted=pcm_remained;
    112 		if (nconverted>nsmps) nconverted=nsmps;
    113 		convertsmps(nconverted,smps,synth.pcm.length-pcm_remained);
    114 
    115 		nsmps-=nconverted;
    116 		smps+=nconverted*2;
    117 
    118 		if (nsmps<=0){
    119 			pcm_remained-=orig_nsmps;
    120 			return orig_nsmps;
    121 		};
    122 	};
    123 
    124 	while (nsmps>0){
    125 		int remaining=0;
    126 		if (stream.next_frame!=NULL){
    127 			remaining=stream.bufend-stream.next_frame;
    128 			memmove(buf,stream.next_frame,remaining);	    
    129 		};
    130 		int readsize=BUFSIZE-remaining;
    131 		int readed=fread(buf+remaining,1,readsize,f);
    132 		if (feof(f)) eof=true;
    133 		if ((eof) || (readed<1)){
    134 			for (int i=0;i<orig_nsmps;i++){
    135 				orig_smps[i]=0;
    136 			};
    137 			return orig_nsmps;
    138 		};
    139 		info.currentsample+=readed;
    140 
    141 
    142 		if (readed!=readsize) {
    143 			for (int i=readed;i<readsize;i++) buf[i+remaining]=0;
    144 		};
    145 		mad_stream_buffer(&stream, buf, BUFSIZE);
    146 		while(1){
    147 			if (mad_frame_decode(&frame, &stream)!=0){
    148 				if (stream.error==MAD_ERROR_BUFLEN) break;
    149 				if (stream.error==MAD_ERROR_LOSTSYNC) continue;
    150 				if (!MAD_RECOVERABLE(stream.error)) {
    151 					printf("Non recoverable MP3 error: 0x%x\n",stream.error);///in caz ca nu este recuperabil
    152 					close();
    153 					return orig_nsmps;
    154 				};
    155 			};
    156 			mad_synth_frame(&synth, &frame);
    157 
    158 			int n=synth.pcm.length;
    159 			if (synth.pcm.samplerate!=0) info.samplerate=synth.pcm.samplerate;
    160 			if (nsmps<synth.pcm.length){
    161 				pcm_remained=synth.pcm.length-nsmps;
    162 				n=nsmps;
    163 			}else{
    164 				pcm_remained=0;
    165 			};
    166 
    167 			convertsmps(n,smps,0);
    168 			nsmps-=n;
    169 			smps+=n*2;
    170 			if (nsmps<=0) return orig_nsmps;
    171 		};
    172 	};
    173 
    174 	return orig_nsmps;
    175 };
    176 void MP3InputS::convertsmps(int nsmps, short int *smps,int pcmstart){
    177 	mad_fixed_t *l=synth.pcm.samples[0],*r=synth.pcm.samples[0];
    178 	if (synth.pcm.channels==2) r=synth.pcm.samples[1];
    179 	l+=pcmstart;r+=pcmstart;
    180 	for (int i=0;i<nsmps;i++){//todo optimize (avoid reconverting r[] for mono samples)
    181 		smps[i*2]=madpcm2short(l[i]);
    182 		smps[i*2+1]=madpcm2short(r[i]);
    183 	};
    184 };
    185 
    186 
    187 short int MP3InputS::madpcm2short(mad_fixed_t x){
    188 	if (x>=MAD_F_ONE) x=MAD_F_ONE-1;
    189 	else if (x<=-MAD_F_ONE) x=-MAD_F_ONE+1;
    190 	int result= x >> (MAD_F_FRACBITS + 1 - 16);
    191 	return result;
    192 };
    193 
    194 void MP3InputS::seek(double pos){
    195 	if (!MP3_opened) return;    
    196 	pcm_remained=0;
    197 
    198 	int p=(int)(pos*info.nsamples);
    199 	info.currentsample=p;
    200 	fseek(f,p,SEEK_SET);
    201 	/*    if (p==0) {
    202 		  fseek(f,0,SEEK_SET);
    203 		  }else{
    204 	//todo add other thing here
    205 	fseek(f,p,SEEK_SET);
    206 	};
    207 	*/
    208 };
    209