mirror of
				https://github.com/ElvishArtisan/rivendell.git
				synced 2025-10-31 06:03:51 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			643 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			643 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // rdrenderer.cpp
 | |
| //
 | |
| // Render a Rivendell log to a single audio object.
 | |
| //
 | |
| //   (C) Copyright 2017-2019 Fred Gleason <fredg@paravelsystems.com>
 | |
| //
 | |
| //   This program is free software; you can redistribute it and/or modify
 | |
| //   it under the terms of the GNU General Public License version 2 as
 | |
| //   published by the Free Software Foundation.
 | |
| //
 | |
| //   This program is distributed in the hope that it will be useful,
 | |
| //   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| //   GNU General Public License for more details.
 | |
| //
 | |
| //   You should have received a copy of the GNU General Public
 | |
| //   License along with this program; if not, write to the Free Software
 | |
| //   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | |
| //
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <math.h>
 | |
| 
 | |
| #include "rdapplication.h"
 | |
| #include "rdaudioconvert.h"
 | |
| #include "rdaudioexport.h"
 | |
| #include "rdaudioimport.h"
 | |
| #include "rdcart.h"
 | |
| #include "rdconf.h"
 | |
| #include "rdcut.h"
 | |
| #include "rdtempdirectory.h"
 | |
| 
 | |
| #include "rdrenderer.h"
 | |
| 
 | |
| __RDRenderLogLine::__RDRenderLogLine(RDLogLine *ll,unsigned chans)
 | |
|   : RDLogLine(*ll)
 | |
| {
 | |
|   ll_cart=NULL;
 | |
|   ll_cut=NULL;
 | |
|   ll_handle=NULL;
 | |
|   ll_channels=chans;
 | |
|   ll_ramp_level=0.0;
 | |
|   ll_ramp_rate=0.0;
 | |
| }
 | |
| 
 | |
| 
 | |
| RDCart *__RDRenderLogLine::cart() const
 | |
| {
 | |
|   return ll_cart;
 | |
| }
 | |
| 
 | |
| 
 | |
| RDCut *__RDRenderLogLine::cut() const
 | |
| {
 | |
|   return ll_cut;
 | |
| }
 | |
| 
 | |
| 
 | |
| SNDFILE *__RDRenderLogLine::handle() const
 | |
| {
 | |
|   return ll_handle;
 | |
| }
 | |
| 
 | |
| 
 | |
| double __RDRenderLogLine::rampLevel() const
 | |
| {
 | |
|   return ll_ramp_level;
 | |
| }
 | |
| 
 | |
| 
 | |
| void __RDRenderLogLine::setRampLevel(double lvl)
 | |
| {
 | |
|   ll_ramp_level=lvl;
 | |
| }
 | |
| 
 | |
| 
 | |
| double __RDRenderLogLine::rampRate() const
 | |
| {
 | |
|   return ll_ramp_rate;
 | |
| }
 | |
| 
 | |
| 
 | |
| void __RDRenderLogLine::setRampRate(double lvl)
 | |
| {
 | |
|   ll_ramp_rate=lvl;
 | |
| }
 | |
| 
 | |
| 
 | |
| void __RDRenderLogLine::setRamp(RDLogLine::TransType next_trans)
 | |
| {
 | |
|   if((next_trans==RDLogLine::Segue)&&(segueStartPoint()>=0)) {
 | |
|     ll_ramp_rate=((double)RD_FADE_DEPTH)/
 | |
|       ((double)FramesFromMsec(segueEndPoint()-segueStartPoint()));
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| bool __RDRenderLogLine::open(const QTime &time)
 | |
| {
 | |
|   QString cutname;
 | |
|   SF_INFO sf_info;
 | |
| 
 | |
|   if(type()==RDLogLine::Cart) {
 | |
|     ll_cart=new RDCart(cartNumber());
 | |
|     if(ll_cart->exists()&&(ll_cart->type()==RDCart::Audio)) {
 | |
|       if(ll_cart->selectCut(&cutname,time)) {
 | |
| 	ll_cut=new RDCut(cutname);
 | |
| 	setStartPoint(ll_cut->startPoint(),RDLogLine::CartPointer);
 | |
| 	setEndPoint(ll_cut->endPoint(),RDLogLine::CartPointer);
 | |
| 	setSegueStartPoint(ll_cut->segueStartPoint(),RDLogLine::CartPointer);
 | |
| 	setSegueEndPoint(ll_cut->segueEndPoint(),RDLogLine::CartPointer);
 | |
| 	QString filename;
 | |
| 	if(GetCutFile(cutname,ll_cut->startPoint(),ll_cut->endPoint(),
 | |
| 		      &filename)) {
 | |
| 	  ll_handle=sf_open(filename,SFM_READ,&sf_info);
 | |
| 	  if(ll_handle!=NULL) {
 | |
|  	    DeleteCutFile(filename);
 | |
| 	    return true;
 | |
| 	  }
 | |
| 	}
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| void __RDRenderLogLine::close()
 | |
| {
 | |
|   sf_close(ll_handle);
 | |
|   ll_handle=NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| QString __RDRenderLogLine::summary() const
 | |
| {
 | |
|   QString ret=QString().sprintf("unknown event [type: %d]",type());
 | |
|   switch(type()) {
 | |
|   case RDLogLine::Cart:
 | |
|     ret=QString().sprintf("cart %06u [",cartNumber())+title()+"]";
 | |
|     break;
 | |
| 	  
 | |
|   case RDLogLine::Marker:
 | |
|     ret="marker ["+markerComment()+"]";
 | |
|     break;
 | |
| 
 | |
|   case RDLogLine::Macro:
 | |
|     ret="macro cart ["+title()+"]";
 | |
|     break;
 | |
| 
 | |
|   case RDLogLine::Chain:
 | |
|     ret="chain-to ["+markerLabel()+"]";
 | |
|     break;
 | |
| 
 | |
|   case RDLogLine::Track:
 | |
|     ret="track marker ["+markerComment()+"]";
 | |
|     break;
 | |
| 
 | |
|   case RDLogLine::MusicLink:
 | |
|     ret="music link";
 | |
|     break;
 | |
| 
 | |
|   case RDLogLine::TrafficLink:
 | |
|     ret="traffic link";
 | |
|     break;
 | |
| 
 | |
|   case RDLogLine::OpenBracket:
 | |
|   case RDLogLine::CloseBracket:
 | |
|   case RDLogLine::UnknownType:
 | |
|     break;
 | |
|   }
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool __RDRenderLogLine::GetCutFile(const QString &cutname,int start_pt,
 | |
| 				   int end_pt,QString *dest_filename) const
 | |
| {
 | |
|   bool ret=false;
 | |
|   RDAudioConvert::ErrorCode conv_err;
 | |
|   RDAudioExport::ErrorCode export_err;
 | |
|   char tempdir[PATH_MAX];
 | |
|   
 | |
|   strncpy(tempdir,RDTempDirectory::basePath()+"/rdrenderXXXXXX",PATH_MAX);
 | |
|   *dest_filename=QString(mkdtemp(tempdir))+"/"+cutname+".wav";
 | |
|   RDAudioExport *conv=new RDAudioExport();
 | |
|   conv->setDestinationFile(*dest_filename);
 | |
|   conv->setCartNumber(RDCut::cartNumber(cutname));
 | |
|   conv->setCutNumber(RDCut::cutNumber(cutname));
 | |
|   RDSettings s;
 | |
|   s.setFormat(RDSettings::Pcm16);
 | |
|   s.setSampleRate(rda->system()->sampleRate());
 | |
|   s.setChannels(ll_channels);
 | |
|   s.setNormalizationLevel(0);
 | |
|   conv->setDestinationSettings(&s);
 | |
|   conv->setRange(start_pt,end_pt);
 | |
|   conv->setEnableMetadata(false);
 | |
|   switch(export_err=conv->runExport(rda->user()->name(),
 | |
| 				    rda->user()->password(),&conv_err)) {
 | |
|   case RDAudioExport::ErrorOk:
 | |
|     ret=true;
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     ret=false;
 | |
|     printf("export err %d [%s]\n",export_err,
 | |
| 	  (const char *)RDAudioExport::errorText(export_err,conv_err).toUtf8());
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   delete conv;
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| 
 | |
| void __RDRenderLogLine::DeleteCutFile(const QString &dest_filename) const
 | |
| {
 | |
|   unlink(dest_filename);
 | |
|   QStringList f0=dest_filename.split("/");
 | |
|   f0.erase(f0.fromLast());
 | |
|   rmdir("/"+f0.join("/"));
 | |
| }
 | |
| 
 | |
| 
 | |
| uint64_t __RDRenderLogLine::FramesFromMsec(uint64_t msec)
 | |
| {
 | |
|   return msec*rda->system()->sampleRate()/1000;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| RDRenderer::RDRenderer(QObject *parent)
 | |
|   : QObject(parent)
 | |
| {
 | |
|   render_total_passes=0;
 | |
| }
 | |
| 
 | |
| 
 | |
| RDRenderer::~RDRenderer()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| bool RDRenderer::renderToFile(const QString &outfile,RDLogEvent *log,
 | |
| 			      RDSettings *s,const QTime &start_time,
 | |
| 			      bool ignore_stops,QString *err_msg,
 | |
| 			      int first_line,int last_line,
 | |
| 			      const QTime &first_time,const QTime &last_time)
 | |
| {
 | |
|   QString temp_output_filename;
 | |
|   char tempdir[PATH_MAX];
 | |
|   bool ok=false;
 | |
|   FILE *f=NULL;
 | |
|   bool ret;
 | |
| 
 | |
|   //
 | |
|   // Verify Destination
 | |
|   //
 | |
|   if((f=fopen(outfile,"w"))==NULL) {
 | |
|     *err_msg=tr("unable to open output file")+" ["+QString(strerror(errno))+"]";
 | |
|     return false;
 | |
|   }
 | |
|   fclose(f);
 | |
| 
 | |
|   if(((s->format()!=RDSettings::Pcm16)&&(s->format()!=RDSettings::Pcm24))||
 | |
|      (s->normalizationLevel()!=0)) {
 | |
|     ProgressMessage("Pass 1 of 2");
 | |
|     render_total_passes=2;
 | |
| 
 | |
|     //
 | |
|     // Get Temporary File
 | |
|     //
 | |
|     strncpy(tempdir,RDTempDirectory::basePath()+"/rdrenderXXXXXX",PATH_MAX);
 | |
|     temp_output_filename=QString(mkdtemp(tempdir))+"/log.wav";
 | |
|     ProgressMessage(tr("Using temporary file")+" \""+temp_output_filename+"\".");
 | |
| 
 | |
|     //
 | |
|     // Render It
 | |
|     //
 | |
|     if(!Render(temp_output_filename,log,s,start_time,ignore_stops,err_msg,
 | |
| 	       first_line,last_line,first_time,last_time)) {
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Convert It
 | |
|     //
 | |
|     ProgressMessage(tr("Pass 2 of 2"));
 | |
|     ProgressMessage(tr("Writing output file"));
 | |
|     ok=ConvertAudio(temp_output_filename,outfile,s,err_msg);
 | |
|     DeleteTempFile(temp_output_filename);
 | |
|     emit lineStarted(log->size()+1,log->size()+1);
 | |
|     if(!ok) {
 | |
|       return false;
 | |
|     }
 | |
|   }
 | |
|   else {
 | |
|     ProgressMessage(tr("Pass 1 of 1"));
 | |
|     render_total_passes=1;
 | |
| 
 | |
|     ret=Render(outfile,log,s,start_time,ignore_stops,err_msg,
 | |
| 	       first_line,last_line,first_time,last_time);
 | |
|     emit lineStarted(log->size(),log->size());
 | |
|     return ret;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool RDRenderer::renderToCart(unsigned cartnum,int cutnum,RDLogEvent *log,
 | |
| 			      RDSettings *s,const QTime &start_time,
 | |
| 			      bool ignore_stops,QString *err_msg,
 | |
| 			      int first_line,int last_line,
 | |
| 			      const QTime &first_time,const QTime &last_time)
 | |
| {
 | |
|   QString temp_output_filename;
 | |
|   char tempdir[PATH_MAX];
 | |
|   bool ok=false;
 | |
| 
 | |
|   if(first_line<0) {
 | |
|     first_line=0;
 | |
|   }
 | |
|   if(last_line<0) {
 | |
|     last_line=log->size();
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check that we won't overflow the 32 bit BWF structures
 | |
|   // when we go to import the rendered log back into the audio store
 | |
|   //
 | |
|   if((double)log->length(first_line,last_line-1)/1000.0>=
 | |
|      (1073741824.0/((double)s->channels()*(double)s->sampleRate()))) {
 | |
|     *err_msg=tr("Rendered log is too long!");
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   ProgressMessage(tr("Pass 1 of 2"));
 | |
|   render_total_passes=2;
 | |
| 
 | |
|   //
 | |
|   // Verify Destination
 | |
|   //
 | |
|   if(!RDCart::exists(cartnum)) {
 | |
|     *err_msg=tr("no such cart");
 | |
|     return false;
 | |
|   }
 | |
|   if(!RDCut::exists(cartnum,cutnum)) {
 | |
|     *err_msg=tr("no such cut");
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get Temporary File
 | |
|   //
 | |
|   strncpy(tempdir,RDTempDirectory::basePath()+"/rdrenderXXXXXX",PATH_MAX);
 | |
|   temp_output_filename=QString(mkdtemp(tempdir))+"/log.wav";
 | |
|   ProgressMessage(tr("Using temporary file")+" \""+temp_output_filename+"\".");
 | |
| 
 | |
|   //
 | |
|   // Render It
 | |
|   //
 | |
|   if(!Render(temp_output_filename,log,s,start_time,ignore_stops,err_msg,
 | |
| 	     first_line,last_line,first_time,last_time)) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Convert It
 | |
|   //
 | |
|   ProgressMessage(tr("Pass 2 of 2"));
 | |
|   ProgressMessage(tr("Importing cart"));
 | |
|   ok=ImportCart(temp_output_filename,cartnum,cutnum,s->channels(),err_msg);
 | |
|   DeleteTempFile(temp_output_filename);
 | |
|   emit lineStarted(log->size()+1,log->size()+1);
 | |
|   if(!ok) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| QStringList RDRenderer::warnings() const
 | |
| {
 | |
|   return render_warnings;
 | |
| }
 | |
| 
 | |
| 
 | |
| void RDRenderer::abort()
 | |
| {
 | |
|   render_abort=true;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool RDRenderer::Render(const QString &outfile,RDLogEvent *log,RDSettings *s,
 | |
| 			const QTime &start_time,bool ignore_stops,
 | |
| 			QString *err_msg,int first_line,int last_line,
 | |
| 			const QTime &first_time,const QTime &last_time)
 | |
| {
 | |
|   float *pcm=NULL;
 | |
|   QTime current_time=start_time;
 | |
|   QString temp_output_filename;
 | |
| 
 | |
|   render_warnings.clear();
 | |
|   render_abort=false;
 | |
| 
 | |
|   //
 | |
|   // Open Output File
 | |
|   //
 | |
|   SF_INFO sf_info;
 | |
|   SNDFILE *sf_out;
 | |
| 
 | |
|   memset(&sf_info,0,sizeof(sf_info));
 | |
|   sf_info.samplerate=rda->system()->sampleRate();
 | |
|   sf_info.channels=s->channels();
 | |
|   if(s->format()==RDSettings::Pcm16) {
 | |
|     sf_info.format=SF_FORMAT_WAV|SF_FORMAT_PCM_16;
 | |
|   }
 | |
|   else {
 | |
|     sf_info.format=SF_FORMAT_WAV|SF_FORMAT_PCM_24;
 | |
|   }
 | |
|   sf_out=sf_open(outfile,SFM_WRITE,&sf_info);
 | |
|   if(sf_out==NULL) {
 | |
|     fprintf(stderr,"rdrender: unable to open output file [%s]\n",
 | |
| 	    sf_strerror(sf_out));
 | |
|     return 1;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Initialize the log
 | |
|   //
 | |
|   std::vector<__RDRenderLogLine *> lls;
 | |
|   for(int i=0;i<log->size();i++) {
 | |
|     lls.push_back(new __RDRenderLogLine(log->logLine(i),s->channels()));
 | |
|     if(ignore_stops&&(lls.back()->transType()==RDLogLine::Stop)) {
 | |
|       lls.back()->setTransType(RDLogLine::Play);
 | |
|     }
 | |
|     if((!first_time.isNull())&&
 | |
|        (lls.back()->timeType()==RDLogLine::Hard)&&
 | |
|        (first_line==-1)&&
 | |
|        (lls.back()->startTime(RDLogLine::Imported)==first_time)) {
 | |
|       first_line=i;
 | |
|     }
 | |
|     if((!last_time.isNull())&&
 | |
|        (lls.back()->timeType()==RDLogLine::Hard)&&
 | |
|        (last_line==-1)&&
 | |
|        (lls.back()->startTime(RDLogLine::Imported)==last_time)) {
 | |
|       last_line=i;
 | |
|     }
 | |
|   }
 | |
|   if((!first_time.isNull())&&(first_line==-1)) {
 | |
|     *err_msg+=tr("first-time event not found");
 | |
|   }
 | |
|   if((!last_time.isNull())&&(last_line==-1)) {
 | |
|     if(!err_msg->isEmpty()) {
 | |
|       *err_msg+=", ";
 | |
|     }
 | |
|     *err_msg+=tr("last-time event not found");
 | |
|   }
 | |
|   if(!err_msg->isEmpty()) {
 | |
|     return false;
 | |
|   }
 | |
|   lls.push_back(new __RDRenderLogLine(new RDLogLine(),s->channels()));
 | |
|   lls.back()->setTransType(RDLogLine::Play);
 | |
|   if((!first_time.isNull())&&(first_line==-1)) {
 | |
|     first_line=log->size();
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Iterate through it
 | |
|   //
 | |
|   for(unsigned i=0;i<lls.size();i++) {
 | |
|     if(render_abort) {
 | |
|       emit lineStarted(log->size()+render_total_passes-1,
 | |
| 		       log->size()+render_total_passes-1);
 | |
|       *err_msg+="Render aborted.\n";
 | |
|       sf_close(sf_out);
 | |
|       return false;
 | |
|     }
 | |
|     emit lineStarted(i,log->size()+render_total_passes-1);
 | |
|     if(((first_line==-1)||(first_line<=(int)i))&&
 | |
|        ((last_line==-1)||(last_line>(int)i))) {
 | |
|       if(lls.at(i)->transType()==RDLogLine::Stop) {
 | |
| 	ProgressMessage(current_time,i,tr("STOP")+" ",lls.at(i)->summary());
 | |
| 	render_warnings.
 | |
| 	  push_back(tr("log render halted at line")+QString().sprintf(" %d ",i)+
 | |
| 		    tr("due to STOP"));
 | |
| 	break;
 | |
|       }
 | |
|       if(lls.at(i)->open(current_time)) {
 | |
| 	ProgressMessage(current_time,i,
 | |
| 			RDLogLine::transText(lls.at(i)->transType()),
 | |
| 		      QString().sprintf(" cart %06u [",lls.at(i)->cartNumber())+
 | |
| 			lls.at(i)->title()+"]");
 | |
| 	sf_count_t frames=0;
 | |
| 	if((lls.at(i+1)->transType()==RDLogLine::Segue)&&
 | |
| 	   (lls.at(i)->segueStartPoint()>=0)) {
 | |
| 	  frames=FramesFromMsec(lls.at(i)->segueStartPoint()-
 | |
| 				lls.at(i)->startPoint());
 | |
| 	  current_time=
 | |
| 	    current_time.addMSecs(lls.at(i)->segueStartPoint()-
 | |
| 				  lls.at(i)->startPoint());
 | |
| 	}
 | |
| 	else {
 | |
| 	  frames=FramesFromMsec(lls.at(i)->endPoint()-
 | |
| 				lls.at(i)->startPoint());
 | |
| 	  current_time=current_time.addMSecs(lls.at(i)->endPoint()-
 | |
| 					     lls.at(i)->startPoint());
 | |
| 	}
 | |
| 	pcm=new float[frames*s->channels()];
 | |
| 	memset(pcm,0,frames*s->channels()*sizeof(float));
 | |
| 
 | |
| 	for(unsigned j=0;j<i;j++) {
 | |
| 	  Sum(pcm,lls.at(j),frames,s->channels());
 | |
| 	}
 | |
| 	Sum(pcm,lls.at(i),frames,s->channels());
 | |
| 	sf_writef_float(sf_out,pcm,frames);
 | |
| 	delete pcm;
 | |
| 	pcm=NULL;
 | |
| 	lls.at(i)->setRamp(lls.at(i+1)->transType());
 | |
|       }
 | |
|       else {
 | |
| 	if(i<(lls.size()-1)) {
 | |
| 	  if(lls.at(i)->type()==RDLogLine::Cart) {
 | |
| 	    ProgressMessage(current_time,i,tr("FAIL"),lls.at(i)->summary()+
 | |
| 			    " ("+tr("NO AUDIO AVAILABLE")+")");
 | |
| 	    render_warnings.
 | |
| 	      push_back(lls.at(i)->summary()+tr("at line")+
 | |
| 			QString().sprintf(" %d ",i)+
 | |
| 			tr("failed to play (NO AUDIO AVAILABLE)"));
 | |
| 	  }
 | |
| 	  else {
 | |
| 	    ProgressMessage(current_time,i,tr("SKIP"),lls.at(i)->summary());
 | |
| 	  }
 | |
| 	}
 | |
| 	else {
 | |
| 	  ProgressMessage(current_time,lls.size()-1,
 | |
| 			  tr("STOP"),tr("--- end of log ---"));
 | |
| 	}
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   sf_close(sf_out);
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| void RDRenderer::Sum(float *pcm_out,__RDRenderLogLine *ll,sf_count_t frames,
 | |
| 		     unsigned chans)
 | |
| {
 | |
|   if(ll->handle()!=NULL) {
 | |
|     float *pcm=new float[frames*chans];
 | |
| 
 | |
|     memset(pcm,0,frames*chans);
 | |
|     sf_count_t n=sf_readf_float(ll->handle(),pcm,frames);
 | |
|     for(sf_count_t i=0;i<n;i+=chans) {
 | |
|       double ratio=exp10(((double)i*ll->rampRate()+ll->rampLevel())/2000.0);
 | |
|       for(sf_count_t j=0;j<chans;j++) {
 | |
| 	pcm_out[i*chans+j]+=ratio*pcm[i*chans+j];
 | |
|       }
 | |
|     }
 | |
|     ll->setRampLevel((double)n*ll->rampRate()+ll->rampLevel());
 | |
|     if(n<frames) {
 | |
|       ll->close();
 | |
|     }
 | |
|     delete pcm;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| bool RDRenderer::ConvertAudio(const QString &srcfile,const QString &dstfile,
 | |
| 			      RDSettings *s,QString *err_msg)
 | |
| {
 | |
|   RDAudioConvert::ErrorCode err_code;
 | |
| 
 | |
|   RDAudioConvert *conv=new RDAudioConvert(this);
 | |
|   conv->setSourceFile(srcfile);
 | |
|   conv->setDestinationFile(dstfile);
 | |
|   conv->setDestinationSettings(s);
 | |
|   err_code=conv->convert();
 | |
|   *err_msg=RDAudioConvert::errorText(err_code);
 | |
|   delete conv;
 | |
| 
 | |
|   return err_code==RDAudioConvert::ErrorOk;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool RDRenderer::ImportCart(const QString &srcfile,unsigned cartnum,int cutnum,
 | |
| 			    unsigned chans,QString *err_msg)
 | |
| {
 | |
|   RDAudioImport::ErrorCode err_import_code;
 | |
|   RDAudioConvert::ErrorCode err_conv_code;
 | |
|   RDSettings settings;
 | |
|   
 | |
|   settings.setChannels(chans);
 | |
|   settings.setNormalizationLevel(0);
 | |
| 
 | |
|   RDAudioImport *conv=new RDAudioImport(this);
 | |
|   conv->setCartNumber(cartnum);
 | |
|   conv->setCutNumber(cutnum);
 | |
|   conv->setSourceFile(srcfile);
 | |
|   conv->setUseMetadata(false);
 | |
|   conv->setDestinationSettings(&settings);
 | |
|   err_import_code=
 | |
|     conv->runImport(rda->user()->name(),rda->user()->password(),&err_conv_code);
 | |
|   *err_msg=RDAudioImport::errorText(err_import_code,err_conv_code);
 | |
|   delete conv;
 | |
|   return err_import_code==RDAudioImport::ErrorOk;
 | |
| }
 | |
| 
 | |
| 
 | |
| void RDRenderer::DeleteTempFile(const QString &filename) const
 | |
| {
 | |
|   unlink(filename);
 | |
|   QStringList f0=filename.split("/");
 | |
|   f0.erase(f0.fromLast());
 | |
|   rmdir("/"+f0.join("/"));
 | |
| }
 | |
| 
 | |
| 
 | |
| uint64_t RDRenderer::FramesFromMsec(uint64_t msec) const
 | |
| {
 | |
|   return msec*rda->system()->sampleRate()/1000;
 | |
| }
 | |
| 
 | |
| 
 | |
| void RDRenderer::ProgressMessage(const QString &msg)
 | |
| {
 | |
|   emit progressMessageSent(msg);
 | |
| }
 | |
| 
 | |
| 
 | |
| void RDRenderer::ProgressMessage(const QTime &time,int line,
 | |
| 				 const QString &trans,const QString &msg)
 | |
| {
 | |
|   QString str=QString().sprintf("%04d : ",line)+
 | |
|     time.toString("hh:mm:ss")+" : "+
 | |
|     QString().sprintf("%-5s",(const char *)trans)+msg;
 | |
|   emit progressMessageSent(str);
 | |
| }
 |