예제 #1
0
int ExportFLAC::Export(AudacityProject *project,
                        int numChannels,
                        const wxString &fName,
                        bool selectionOnly,
                        double t0,
                        double t1,
                        MixerSpec *mixerSpec,
                        const Tags *metadata,
                        int WXUNUSED(subformat))
{
   double    rate    = project->GetRate();
   TrackList *tracks = project->GetTracks();

   wxLogNull logNo;            // temporarily disable wxWidgets error messages
   int updateResult = eProgressSuccess;

   int levelPref;
   gPrefs->Read(wxT("/FileFormats/FLACLevel"), &levelPref, 5);

   wxString bitDepthPref =
      gPrefs->Read(wxT("/FileFormats/FLACBitDepth"), wxT("16"));

   FLAC::Encoder::File encoder;

#ifdef LEGACY_FLAC
   encoder.set_filename(OSOUTPUT(fName));
#endif
   encoder.set_channels(numChannels);
   encoder.set_sample_rate(lrint(rate));

   // See note in GetMetadata() about a bug in libflac++ 1.1.2
   if (!GetMetadata(project, metadata)) {
      return false;
   }

   if (mMetadata) {
      encoder.set_metadata(&mMetadata, 1);
   }

   sampleFormat format;
   if (bitDepthPref == wxT("24")) {
      format = int24Sample;
      encoder.set_bits_per_sample(24);
   } else { //convert float to 16 bits
      format = int16Sample;
      encoder.set_bits_per_sample(16);
   }

   // Duplicate the flac command line compression levels
   if (levelPref < 0 || levelPref > 8) {
      levelPref = 5;
   }
   encoder.set_do_exhaustive_model_search(flacLevels[levelPref].do_exhaustive_model_search);
   encoder.set_do_escape_coding(flacLevels[levelPref].do_escape_coding);
   if (numChannels != 2) {
      encoder.set_do_mid_side_stereo(false);
      encoder.set_loose_mid_side_stereo(false);
   }
   else {
      encoder.set_do_mid_side_stereo(flacLevels[levelPref].do_mid_side_stereo);
      encoder.set_loose_mid_side_stereo(flacLevels[levelPref].loose_mid_side_stereo);
   }
   encoder.set_qlp_coeff_precision(flacLevels[levelPref].qlp_coeff_precision);
   encoder.set_min_residual_partition_order(flacLevels[levelPref].min_residual_partition_order);
   encoder.set_max_residual_partition_order(flacLevels[levelPref].max_residual_partition_order);
   encoder.set_rice_parameter_search_dist(flacLevels[levelPref].rice_parameter_search_dist);
   encoder.set_max_lpc_order(flacLevels[levelPref].max_lpc_order);

#ifdef LEGACY_FLAC
   encoder.init();
#else
   wxFFile f;     // will be closed when it goes out of scope
   if (!f.Open(fName, wxT("w+b"))) {
      wxMessageBox(wxString::Format(_("FLAC export couldn't open %s"), fName.c_str()));
      return false;
   }

   // Even though there is an init() method that takes a filename, use the one that
   // takes a file handle because wxWidgets can open a file with a Unicode name and
   // libflac can't (under Windows).
   int status = encoder.init(f.fp());
   if (status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
      wxMessageBox(wxString::Format(_("FLAC encoder failed to initialize\nStatus: %d"), status));
      return false;
   }
#endif

   if (mMetadata) {
      ::FLAC__metadata_object_delete(mMetadata);
   }

   int numWaveTracks;
   WaveTrack **waveTracks;
   tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks);
   Mixer *mixer = CreateMixer(numWaveTracks, waveTracks,
                            tracks->GetTimeTrack(),
                            t0, t1,
                            numChannels, SAMPLES_PER_RUN, false,
                            rate, format, true, mixerSpec);
   delete [] waveTracks;

   int i, j;
   FLAC__int32 **tmpsmplbuf = new FLAC__int32*[numChannels];
   for (i = 0; i < numChannels; i++) {
      tmpsmplbuf[i] = (FLAC__int32 *) calloc(SAMPLES_PER_RUN, sizeof(FLAC__int32));
   }

   {
      ProgressDialog progress(wxFileName(fName).GetName(),
         selectionOnly ?
         _("Exporting the selected audio as FLAC") :
         _("Exporting the entire project as FLAC"));

      while (updateResult == eProgressSuccess) {
         sampleCount samplesThisRun = mixer->Process(SAMPLES_PER_RUN);
         if (samplesThisRun == 0) { //stop encoding
            break;
         }
         else {
            for (i = 0; i < numChannels; i++) {
               samplePtr mixed = mixer->GetBuffer(i);
               if (format == int24Sample) {
                  for (j = 0; j < samplesThisRun; j++) {
                     tmpsmplbuf[i][j] = ((int *)mixed)[j];
                  }
               }
               else {
                  for (j = 0; j < samplesThisRun; j++) {
                     tmpsmplbuf[i][j] = ((short *)mixed)[j];
                  }
               }
            }
            encoder.process(tmpsmplbuf, samplesThisRun);
         }
         updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0);
      }
      f.Detach(); // libflac closes the file
      encoder.finish();
   }

   for (i = 0; i < numChannels; i++) {
      free(tmpsmplbuf[i]);
   }
   delete mixer;

   delete[] tmpsmplbuf;

   return updateResult;
}
예제 #2
0
파일: Mix.cpp 프로젝트: ruthmagnus/audacity
bool MixAndRender(TrackList *tracks, TrackFactory *trackFactory,
                  double rate, sampleFormat format,
                  double startTime, double endTime,
                  WaveTrack **newLeft, WaveTrack **newRight)
{
   // This function was formerly known as "Quick Mix".  It takes one or
   // more tracks as input; of all tracks that are selected, it mixes
   // them together, applying any envelopes, amplitude gain, panning,
   // and real-time effects in the process.  The resulting pair of
   // tracks (stereo) are "rendered" and have no effects, gain, panning,
   // or envelopes.

   WaveTrack **waveArray;
   Track *t;
   int numWaves = 0;
   int numMono = 0;
   bool mono = false;
   int w;

   TrackListIterator iter(tracks);

   t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == Track::Wave) {
         numWaves++;
         float pan = ((WaveTrack*)t)->GetPan();
         if (t->GetChannel() == Track::MonoChannel && pan == 0)
            numMono++;
      }
      t = iter.Next();
   }

   if (numMono == numWaves)
      mono = true;

   double totalTime = 0.0;

   waveArray = new WaveTrack *[numWaves];
   w = 0;
   t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == Track::Wave) {
         waveArray[w++] = (WaveTrack *) t;
         if (t->GetEndTime() > totalTime)
            totalTime = t->GetEndTime();
      }
      t = iter.Next();
   }

   WaveTrack *mixLeft = trackFactory->NewWaveTrack(format, rate);
   mixLeft->SetName(_("Mix"));
   WaveTrack *mixRight = 0;
   if (mono) {
      mixLeft->SetChannel(Track::MonoChannel);
   }
   else {
      mixRight = trackFactory->NewWaveTrack(format, rate);
      mixRight->SetName(_("Mix"));
      mixLeft->SetChannel(Track::LeftChannel);
      mixRight->SetChannel(Track::RightChannel);
      mixLeft->SetLinked(true);
      mixRight->SetTeamed(true);
   }

   int maxBlockLen = mixLeft->GetIdealBlockSize();

   if (startTime == endTime) {
      startTime = 0.0;
      endTime = totalTime;
   }

   Mixer *mixer = new Mixer(numWaves, waveArray, tracks->GetTimeTrack(),
                            startTime, endTime, mono ? 1 : 2, maxBlockLen, false,
                            rate, format);

   wxYield();
   GetActiveProject()->ProgressShow(_NoAcc("&Mix and Render"),
                                    _("Mixing and rendering tracks"));
   wxBusyCursor busy;
   
   bool cancelling = false;
   while(!cancelling) {
      sampleCount blockLen = mixer->Process(maxBlockLen);

      if (blockLen == 0)
         break;

      if (mono) {
         samplePtr buffer = mixer->GetBuffer();
         mixLeft->Append(buffer, format, blockLen);
      }
      else {
         samplePtr buffer;
         buffer = mixer->GetBuffer(0);
         mixLeft->Append(buffer, format, blockLen);
         buffer = mixer->GetBuffer(1);
         mixRight->Append(buffer, format, blockLen);
      }

      int progressvalue = int (1000 * (mixer->MixGetCurrentTime() / totalTime));
      cancelling = !GetActiveProject()->ProgressUpdate(progressvalue);
   }

   GetActiveProject()->ProgressHide();

   mixLeft->Flush();
   *newLeft = mixLeft;
   if (!mono) {
      mixRight->Flush();
      *newRight = mixRight;
   }

#if 0
   int elapsedMS = wxGetElapsedTime();
   double elapsedTime = elapsedMS * 0.001;
   double maxTracks = totalTime / (elapsedTime / numWaves);

   // Note: these shouldn't be translated - they're for debugging
   // and profiling only.
   printf("      Tracks: %d\n", numWaves);
   printf("  Mix length: %f sec\n", totalTime);
   printf("Elapsed time: %f sec\n", elapsedTime);
   printf("Max number of tracks to mix in real time: %f\n", maxTracks);
#endif

   delete[] waveArray;
   delete mixer;

   return true;
}
예제 #3
0
파일: Mix.cpp 프로젝트: andreipaga/audacity
bool QuickMix(TrackList *tracks, DirManager *dirManager,
              double rate, sampleFormat format)
{
   WaveTrack **waveArray;
   VTrack *t;
   int numWaves = 0;
   int numLeft = 0;
   int numRight = 0;
   int numMono = 0;
   bool mono = false;
   int w;

   TrackListIterator iter(tracks);

   t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == VTrack::Wave) {
         numWaves++;
         switch (t->GetChannel()) {
         case VTrack::MonoChannel:
            numLeft++;
            numRight++;
            numMono++;
            break;
         case VTrack::LeftChannel:
            numLeft++;
            break;
         case VTrack::RightChannel:
            numRight++;
            break;
         }
      }
      t = iter.Next();
   }

   if (numMono == numWaves || numLeft == numWaves || numRight == numWaves)
      mono = true;

   double totalTime = 0.0;

   waveArray = new WaveTrack *[numWaves];
   w = 0;
   t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == VTrack::Wave) {
         waveArray[w++] = (WaveTrack *) t;
         if (t->GetMaxLen() > totalTime)
            totalTime = t->GetMaxLen();
      }
      t = iter.Next();
   }

   WaveTrack *mixLeft = new WaveTrack(dirManager);
   mixLeft->SetSampleFormat(format);
   mixLeft->SetRate(rate);
   mixLeft->SetChannel(VTrack::MonoChannel);
   mixLeft->SetName(_("Mix"));
   WaveTrack *mixRight = 0;
   if (!mono) {
      mixRight = new WaveTrack(dirManager);
      mixRight->SetSampleFormat(format);
      mixRight->SetRate(rate);
      mixRight->SetName(_("Mix"));
      mixLeft->SetChannel(VTrack::LeftChannel);
      mixRight->SetChannel(VTrack::RightChannel);
      mixLeft->SetLinked(true);
   }

   int maxBlockLen = mixLeft->GetIdealBlockSize();
   double maxBlockTime = maxBlockLen / mixLeft->GetRate();

   Mixer *mixer = new Mixer(mono ? 1 : 2, maxBlockLen, false,
                            rate, format);

   wxProgressDialog *progress = NULL;
   wxYield();
   wxStartTimer();
   wxBusyCursor busy;

   double tt = 0.0;
   while (tt < totalTime) {

      double blockTime = maxBlockTime;
      if (tt + blockTime > totalTime)
         blockTime = totalTime - tt;
      int blockLen = int (blockTime * mixLeft->GetRate());

      mixer->Clear();

      for (int i = 0; i < numWaves; i++) {
         if (mono)
            mixer->MixMono(waveArray[i], tt, tt + blockTime);
         else {
            switch (waveArray[i]->GetChannel()) {
            case VTrack::LeftChannel:
               mixer->MixLeft(waveArray[i], tt, tt + blockTime);
               break;
            case VTrack::RightChannel:
               mixer->MixRight(waveArray[i], tt, tt + blockTime);
               break;
            case VTrack::MonoChannel:
               mixer->MixMono(waveArray[i], tt, tt + blockTime);
               break;
            }
         }
      }

      if (mono) {
         samplePtr buffer = mixer->GetBuffer();
         mixLeft->Append(buffer, format, blockLen);
      } else {
         samplePtr buffer;
         buffer = mixer->GetBuffer(0);
         mixLeft->Append(buffer, format, blockLen);
         buffer = mixer->GetBuffer(1);
         mixRight->Append(buffer, format, blockLen);
      }

      tt += blockTime;

      if (!progress && wxGetElapsedTime(false) > 500) {
         progress =
             new wxProgressDialog(_("Quick Mix"), _("Mixing tracks"), 1000);
      }
      if (progress) {
         int progressvalue = int (1000 * (tt / totalTime));
         progress->Update(progressvalue);
      }
   }

   tracks->Add(mixLeft);
   if (!mono)
      tracks->Add(mixRight);

   delete progress;

   int elapsedMS = wxGetElapsedTime();
   double elapsedTime = elapsedMS * 0.001;
   double maxTracks = totalTime / (elapsedTime / numWaves);

#ifdef __WXGTK__
   printf(_("      Tracks: %d\n"), numWaves);
   printf(_("  Mix length: %f sec\n"), totalTime);
   printf(_("Elapsed time: %f sec\n"), elapsedTime);
   printf(_("Max number of tracks to mix in real time: %f\n"), maxTracks);
#endif

   delete waveArray;
   delete mixer;

   return true;
}
예제 #4
0
bool ExportFFmpeg::EncodeAudioFrame(int16_t *pFrame, int frameSize)
{
   AVPacket	pkt;
   int		nBytesToWrite = 0;
   uint8_t *	pRawSamples = NULL;
   int		nAudioFrameSizeOut = mEncAudioCodecCtx->frame_size * mEncAudioCodecCtx->channels * sizeof(int16_t);
   if (mEncAudioCodecCtx->frame_size == 1) nAudioFrameSizeOut = mEncAudioEncodedBufSiz;
   int      ret;

   nBytesToWrite = frameSize;
   pRawSamples  = (uint8_t*)pFrame;
#if FFMPEG_STABLE
   FFmpegLibsInst->av_fifo_realloc(&mEncAudioFifo, FFmpegLibsInst->av_fifo_size(&mEncAudioFifo) + frameSize);
#else
   FFmpegLibsInst->av_fifo_realloc2(mEncAudioFifo, FFmpegLibsInst->av_fifo_size(mEncAudioFifo) + frameSize);
#endif
   // Put the raw audio samples into the FIFO.
#if FFMPEG_STABLE
   ret = FFmpegLibsInst->av_fifo_generic_write(&mEncAudioFifo, pRawSamples, nBytesToWrite,NULL);
#else
   ret = FFmpegLibsInst->av_fifo_generic_write(mEncAudioFifo, pRawSamples, nBytesToWrite,NULL);
#endif
   wxASSERT(ret == nBytesToWrite);

   // Read raw audio samples out of the FIFO in nAudioFrameSizeOut byte-sized groups to encode.
#if FFMPEG_STABLE
   while ((ret = FFmpegLibsInst->av_fifo_size(&mEncAudioFifo)) >= nAudioFrameSizeOut)
   {
      ret = FFmpegLibsInst->av_fifo_read(&mEncAudioFifo, mEncAudioFifoOutBuf, nAudioFrameSizeOut);
#else
   while ((ret = FFmpegLibsInst->av_fifo_size(mEncAudioFifo)) >= nAudioFrameSizeOut)
   {
      ret = FFmpegLibsInst->av_fifo_generic_read(mEncAudioFifo, mEncAudioFifoOutBuf, nAudioFrameSizeOut, NULL);
#endif
      FFmpegLibsInst->av_init_packet(&pkt);

      pkt.size = FFmpegLibsInst->avcodec_encode_audio(mEncAudioCodecCtx, 
         mEncAudioEncodedBuf, mEncAudioEncodedBufSiz,		// out
         (int16_t*)mEncAudioFifoOutBuf);				// in
      if (mEncAudioCodecCtx->frame_size == 1) { wxASSERT(pkt.size == mEncAudioEncodedBufSiz); }
      if (pkt.size < 0)
      {
         wxLogMessage(wxT("FFmpeg : ERROR - Can't encode audio frame."));
         return false;
      }

      // Rescale from the codec time_base to the AVStream time_base.
      if (mEncAudioCodecCtx->coded_frame && mEncAudioCodecCtx->coded_frame->pts != int64_t(AV_NOPTS_VALUE))
         pkt.pts = FFmpegLibsInst->av_rescale_q(mEncAudioCodecCtx->coded_frame->pts, mEncAudioCodecCtx->time_base, mEncAudioStream->time_base);
      //wxLogMessage(wxT("FFmpeg : (%d) Writing audio frame with PTS: %lld."), mEncAudioCodecCtx->frame_number, pkt.pts);

      pkt.stream_index = mEncAudioStream->index;
      pkt.data = mEncAudioEncodedBuf;
      pkt.flags |= PKT_FLAG_KEY;

      // Write the encoded audio frame to the output file.
      if ((ret = FFmpegLibsInst->av_interleaved_write_frame(mEncFormatCtx, &pkt)) != 0)
      {
         wxLogMessage(wxT("FFmpeg : ERROR - Failed to write audio frame to file."));
         return false;
      }
   }
   return true;
}


int ExportFFmpeg::Export(AudacityProject *project,
                       int channels, wxString fName,
                       bool selectionOnly, double t0, double t1, MixerSpec *mixerSpec, Tags *metadata, int subformat)
{
   if (!CheckFFmpegPresence())
      return false;
   mChannels = channels;
   // subformat index may not correspond directly to fmts[] index, convert it
   mSubFormat = AdjustFormatIndex(subformat);
   if (channels > ExportFFmpegOptions::fmts[mSubFormat].maxchannels)
   {
      wxLogMessage(wxT("Attempted to export %d channels, but max. channels = %d"),channels,ExportFFmpegOptions::fmts[mSubFormat].maxchannels);
      wxMessageBox(wxString::Format(_("Attempted to export %d channels, but max. channels for selected output format is %d"),channels,ExportFFmpegOptions::fmts[mSubFormat].maxchannels),_("Error"));
      return false;
   }
   mName = fName;
   TrackList *tracks = project->GetTracks();
   bool ret = true;

   if (mSubFormat >= FMT_LAST) return false;
   
   wxString shortname(ExportFFmpegOptions::fmts[mSubFormat].shortname);
   if (mSubFormat == FMT_OTHER)
      shortname = gPrefs->Read(wxT("/FileFormats/FFmpegFormat"),wxT("matroska"));
   ret = Init(shortname.mb_str(),project, metadata);

   if (!ret) return false;

   int pcmBufferSize = 1024;
   int numWaveTracks;
   WaveTrack **waveTracks;
   tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks);
   Mixer *mixer = new Mixer(numWaveTracks, waveTracks,
      tracks->GetTimeTrack(),
      t0, t1,
      channels, pcmBufferSize, true,
      mSampleRate, int16Sample, true, mixerSpec);
   delete [] waveTracks;

   ProgressDialog *progress = new ProgressDialog(wxFileName(fName).GetName(),
      selectionOnly ?
      wxString::Format(_("Exporting selected audio as %s"), ExportFFmpegOptions::fmts[mSubFormat].description) :
   wxString::Format(_("Exporting entire file as %s"), ExportFFmpegOptions::fmts[mSubFormat].description));

   int updateResult = eProgressSuccess;

   while(updateResult == eProgressSuccess) {
      sampleCount pcmNumSamples = mixer->Process(pcmBufferSize);

      if (pcmNumSamples == 0)
         break;

      short *pcmBuffer = (short *)mixer->GetBuffer();

      EncodeAudioFrame(pcmBuffer,(pcmNumSamples)*sizeof(int16_t)*mChannels);

      updateResult = progress->Update(mixer->MixGetCurrentTime()-t0, t1-t0);
   }

   delete progress;

   delete mixer;

   Finalize();

   return updateResult;
}

void AddStringTagUTF8(char field[], int size, wxString value)
{
      memset(field,0,size);
      memcpy(field,value.ToUTF8(),(int)strlen(value.ToUTF8()) > size -1 ? size -1 : strlen(value.ToUTF8()));
}
예제 #5
0
bool ExportOGG(AudacityProject *project,
               bool stereo, wxString fName,
               bool selectionOnly, double t0, double t1)
{
   double    rate    = project->GetRate();
   wxWindow  *parent = project;
   TrackList *tracks = project->GetTracks();
   double    quality = (gPrefs->Read("/FileFormats/OggExportQuality", 50)/(float)100.0);

   wxLogNull logNo;            // temporarily disable wxWindows error messages 
   bool      cancelling = false;

   wxFFile outFile(fName, "wb");

   if(!outFile.IsOpened()) {
      wxMessageBox(_("Unable to open target file for writing"));
      return false;
   }

   // All the Ogg and Vorbis encoding data
   ogg_stream_state stream;
   ogg_page         page;
   ogg_packet       packet;

   vorbis_info      info;
   vorbis_comment   comment;
   vorbis_dsp_state dsp;
   vorbis_block     block;

   // Encoding setup
   vorbis_info_init(&info);
   vorbis_encode_init_vbr(&info, stereo ? 2 : 1, int(rate + 0.5), quality);

   vorbis_comment_init(&comment);
   // If we wanted to add comments, we would do it here

   // Set up analysis state and auxiliary encoding storage
   vorbis_analysis_init(&dsp, &info);
   vorbis_block_init(&dsp, &block);

   // Set up packet->stream encoder.  According to encoder example,
   // a random serial number makes it more likely that you can make
   // chained streams with concatenation.
   srand(time(NULL));
   ogg_stream_init(&stream, rand());

   // First we need to write the required headers:
   //    1. The Ogg bitstream header, which contains codec setup params
   //    2. The Vorbis comment header
   //    3. The bitstream codebook.
   //
   // After we create those our responsibility is complete, libvorbis will
   // take care of any other ogg bistream constraints (again, according
   // to the example encoder source)
   ogg_packet bitstream_header;
   ogg_packet comment_header;
   ogg_packet codebook_header;

   vorbis_analysis_headerout(&dsp, &comment, &bitstream_header, &comment_header,
         &codebook_header);

   // Place these headers into the stream
   ogg_stream_packetin(&stream, &bitstream_header);
   ogg_stream_packetin(&stream, &comment_header);
   ogg_stream_packetin(&stream, &codebook_header);

   // Flushing these headers now guarentees that audio data will
   // start on a new page, which apparently makes streaming easier
   ogg_stream_flush(&stream, &page);
   outFile.Write(page.header, page.header_len);
   outFile.Write(page.body, page.body_len);

   double t = t0;
   bool   done = false;
   wxProgressDialog *progress = NULL;

   wxYield();
   wxStartTimer();

   while(!done && !cancelling){
      float       deltat = (float)SAMPLES_PER_RUN / rate;
      sampleCount samplesThisRun = SAMPLES_PER_RUN;
      Mixer       *mixer = new Mixer(stereo ? 2 : 1, SAMPLES_PER_RUN, 
            /* interleaved = */ false, rate, floatSample);

      if(t + deltat > t1) {
         done = true;
         deltat = t1 - t;
         samplesThisRun = int(deltat * rate + 0.5);
      }
      
      mixer->Clear();

      TrackListIterator iter(tracks);
      Track *tr = iter.First();
      while (tr) {
         if (tr->GetKind() == Track::Wave) {
            if (tr->GetSelected() || !selectionOnly) {
               if (tr->GetChannel() == Track::MonoChannel)
                  mixer->MixMono((WaveTrack *) tr, t, t + deltat);
               else if (tr->GetChannel() == Track::LeftChannel)
                  mixer->MixLeft((WaveTrack *) tr, t, t + deltat);
               else if (tr->GetChannel() == Track::RightChannel)
                  mixer->MixRight((WaveTrack *) tr, t, t + deltat);
            }
         }
         tr = iter.Next();
      }
      
      float **vorbis_buffer = vorbis_analysis_buffer(&dsp, SAMPLES_PER_RUN);
      
      float *left = (float *)mixer->GetBuffer(0);
      memcpy(vorbis_buffer[0], left, sizeof(float)*SAMPLES_PER_RUN);

      if(stereo) {
         float *right = (float *)mixer->GetBuffer(1);
         memcpy(vorbis_buffer[1], right, sizeof(float)*SAMPLES_PER_RUN);
      }

      // tell the encoder how many samples we have
      vorbis_analysis_wrote(&dsp, samplesThisRun);

      // I don't understand what this call does, so here is the comment
      // from the example, verbatim:
      //
      //    vorbis does some data preanalysis, then divvies up blocks
      //    for more involved (potentially parallel) processing. Get
      //    a single block for encoding now
      while(vorbis_analysis_blockout(&dsp, &block) == 1) {

         // analysis, assume we want to use bitrate management
         vorbis_analysis(&block, NULL);
         vorbis_bitrate_addblock(&block);

         while(vorbis_bitrate_flushpacket(&dsp, &packet)) {

            // add the packet to the bitstream
            ogg_stream_packetin(&stream, &packet);
            int result = ogg_stream_pageout(&stream, &page);

            if(result != 0) {
               outFile.Write(page.header, page.header_len);
               outFile.Write(page.body, page.body_len);
            }
         }
      }

      if(progress)
         cancelling = !progress->Update(int (((t - t0) * 1000) / (t1 - t0) + 0.5));
      else if(wxGetElapsedTime(false) > 500) {
            
         wxString message = selectionOnly ?
            _("Exporting the selected audio as Ogg Vorbis") :
            _("Exporting the entire project as Ogg Vorbis");

         progress = new wxProgressDialog(
               _("Export"),
               message,
               1000,
               parent,
               wxPD_CAN_ABORT | wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
      }

      delete mixer;
      t += deltat;
   }

   outFile.Close();

   if(progress)
      delete progress;

   return true;
}
예제 #6
0
bool ExportPCM(AudacityProject *project,
               wxString format, bool stereo, wxString fName,
               bool selectionOnly, double t0, double t1)
{
    wxMessageBox("In process of being rewritten, sorry...");

#if 0

    double rate = project->GetRate();
    wxWindow *parent = project;
    TrackList *tracks = project->GetTracks();

    int header = SND_HEAD_NONE;
#ifdef __WXMAC__
    bool trackMarkers = false;
#endif

    if (format == "WAV")
        header = SND_HEAD_WAVE;
    else if (format == "AIFF")
        header = SND_HEAD_AIFF;
    else if (format == "IRCAM")
        header = SND_HEAD_IRCAM;
    else if (format == "AU")
        header = SND_HEAD_NEXT;
#ifdef __WXMAC__
    else if (format == "AIFF with track markers") {
        header = SND_HEAD_AIFF;
        trackMarkers = true;
    }
#endif


    // Use snd library to export file

    snd_node sndfile;
    snd_node sndbuffer;

    sndfile.device = SND_DEVICE_FILE;
    sndfile.write_flag = SND_WRITE;
    strcpy(sndfile.u.file.filename, (const char *) fName);
    sndfile.u.file.file = 0;
    sndfile.u.file.header = header;
    sndfile.u.file.byte_offset = 0;
    sndfile.u.file.end_offset = 0;
    sndfile.u.file.swap = 0;
    sndfile.format.channels = stereo ? 2 : 1;
    sndfile.format.mode = SND_MODE_PCM;  // SND_MODE_FLOAT
    sndfile.format.bits = 16;
    sndfile.format.srate = int (rate + 0.5);

    int err;
    long flags = 0;

    err = snd_open(&sndfile, &flags);
    if (err) {
        wxMessageBox("Could not write to file.");
        return false;
    }

    sndbuffer.device = SND_DEVICE_MEM;
    sndbuffer.write_flag = SND_READ;
    sndbuffer.u.mem.buffer_max = 0;
    sndbuffer.u.mem.buffer = 0;
    sndbuffer.u.mem.buffer_len = 0;
    sndbuffer.u.mem.buffer_pos = 0;
    sndbuffer.format.channels = stereo ? 2 : 1;
    sndbuffer.format.mode = SND_MODE_PCM;        // SND_MODE_FLOAT
    sndbuffer.format.bits = 16;
    sndbuffer.format.srate = int (rate + 0.5);

    double timeStep = 10.0;      // write in blocks of 10 secs

    wxProgressDialog *progress = NULL;
    wxYield();
    wxStartTimer();
    wxBusyCursor busy;
    bool cancelling = false;

    double t = t0;

    while (t < t1 && !cancelling) {

        double deltat = timeStep;
        if (t + deltat > t1)
            deltat = t1 - t;

        sampleCount numSamples = int (deltat * rate + 0.5);

        Mixer *mixer = new Mixer(stereo ? 2 : 1, numSamples, true, rate);
        wxASSERT(mixer);
        mixer->Clear();

        char *buffer = new char[numSamples * 2 * sndbuffer.format.channels];
        wxASSERT(buffer);

        TrackListIterator iter(tracks);
        VTrack *tr = iter.First();
        while (tr) {
            if (tr->GetKind() == VTrack::Wave) {
                if (tr->selected || !selectionOnly) {
                    if (tr->channel == VTrack::MonoChannel)
                        mixer->MixMono((WaveTrack *) tr, t, t + deltat);
                    if (tr->channel == VTrack::LeftChannel)
                        mixer->MixLeft((WaveTrack *) tr, t, t + deltat);
                    if (tr->channel == VTrack::RightChannel)
                        mixer->MixRight((WaveTrack *) tr, t, t + deltat);
                }
            }
            tr = iter.Next();
        }

        sampleType *mixed = mixer->GetBuffer();

        long b2 = snd_convert(&sndfile, buffer,   // to
                              &sndbuffer, mixed, numSamples);     // from

        snd_write(&sndfile, buffer, b2);

        t += deltat;

        if (!progress && wxGetElapsedTime(false) > 500) {

            wxString message;

            if (selectionOnly)
                message =
                    wxString::
                    Format("Exporting the selected audio as a %s file",
                           (const char *) format);
            else
                message =
                    wxString::
                    Format("Exporting the entire project as a %s file",
                           (const char *) format);

            progress =
                new wxProgressDialog("Export",
                                     message,
                                     1000,
                                     parent,
                                     wxPD_CAN_ABORT |
                                     wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
        }
        if (progress) {
            cancelling =
                !progress->Update(int (((t - t0) * 1000) / (t1 - t0) + 0.5));
        }

        delete mixer;
        delete[]buffer;
    }

    snd_close(&sndfile);

#ifdef __WXMAC__

    FSSpec spec;

    wxMacFilename2FSSpec(fName, &spec);

    if (trackMarkers) {
        // Export the label track as "CD Spin Doctor" files

        LabelTrack *labels = NULL;
        TrackListIterator iter(tracks);
        VTrack *t = iter.First();
        while (t && !labels) {
            if (t->GetKind() == VTrack::Label)
                labels = (LabelTrack *) t;
            t = iter.Next();
        }
        if (labels) {
            FSpCreateResFile(&spec, 'AIFF', AUDACITY_CREATOR, 0);
            int resFile = FSpOpenResFile(&spec, fsWrPerm);
            if (resFile == -1) {
                int x = ResError();
            }
            if (resFile != -1) {
                UseResFile(resFile);

                int numLabels = labels->mLabels.Count();
                for (int i = 0; i < numLabels; i++) {
                    int startBlock = (int) (labels->mLabels[i]->t * 75);
                    int lenBlock;
                    if (i < numLabels - 1)
                        lenBlock =
                            (int) ((labels->mLabels[i + 1]->t -
                                    labels->mLabels[i]->t) * 75);
                    else
                        lenBlock =
                            (int) ((tracks->GetMaxLen() -
                                    labels->mLabels[i]->t) * 75);
                    int startSample = startBlock * 1176 + 54;
                    int lenSample = lenBlock * 1176 + 54;

                    Handle theHandle = NewHandle(50);
                    HLock(theHandle);
                    char *data = (char *) (*theHandle);
                    *(int *) &data[0] = startSample;
                    *(int *) &data[4] = lenSample;
                    *(int *) &data[8] = startBlock;
                    *(int *) &data[12] = lenBlock;
                    *(short *) &data[16] = i + 1;

                    wxString title = labels->mLabels[i]->title;
                    if (title.Length() > 31)
                        title = title.Left(31);
                    data[18] = title.Length();
                    strcpy(&data[19], (const char *) title);

                    HUnlock(theHandle);
                    AddResource(theHandle, 'SdCv', 128 + i, "\p");
                }
                CloseResFile(resFile);

                wxMessageBox("Saved track information with file.");
            }
        }
    }

    FInfo finfo;
    if (FSpGetFInfo(&spec, &finfo) == noErr) {
        switch (header) {
        case SND_HEAD_AIFF:
            finfo.fdType = 'AIFF';
            break;
        case SND_HEAD_IRCAM:
            finfo.fdType = 'IRCA';
            break;
        case SND_HEAD_NEXT:
            finfo.fdType = 'AU  ';
            break;
        case SND_HEAD_WAVE:
            finfo.fdType = 'WAVE';
            break;
        }

        finfo.fdCreator = AUDACITY_CREATOR;

        FSpSetFInfo(&spec, &finfo);
    }
#endif

    if (progress)
        delete progress;

    return true;

#endif

    return false;

}
예제 #7
0
bool PCMExporter::Export(const wxString & filename)
{

  mFileName = filename;
  //Unless it has been changed, use the project rate
  if(!mOutRate) 
    mOutRate = mProject->GetRate();
  
  wxWindow    *parent = mProject;
  TrackList   *tracks = mProject->GetTracks();

  wxString     formatStr;
  SF_INFO      info;
  SNDFILE     *sf = NULL;
  int          err;

   formatStr = sf_header_name(mSoundFileFormat & SF_FORMAT_TYPEMASK);

   // Use libsndfile to export file

   info.samplerate = mOutRate;
   info.frames = (unsigned int)((m_t1 - m_t0)*(double)mOutRate + 0.5);
   info.channels = mChannels;
   info.format = mSoundFileFormat;
   info.sections = 1;
   info.seekable = 0;

   // If we can't export exactly the format they requested,
   // try the default format for that header type...
   if (!sf_format_check(&info))
      info.format = (info.format & SF_FORMAT_TYPEMASK);
   if (!sf_format_check(&info)) {
      wxMessageBox(_("Cannot export audio in this format."));
      return false;
   }

   sf = sf_open((const char *)mFileName, SFM_WRITE, &info);
   if (!sf) {
      wxMessageBox(wxString::Format(_("Cannot export audio to %s"),
                                    (const char *)mFileName));
      return false;
   }

   //Determine what format the track is currently in, to avoid
   //multiple conversions.
   sampleFormat format;
   if (sf_subtype_more_than_16_bits(info.format))
      format = floatSample;
   else
      format = int16Sample;

   int maxBlockLen = 44100 * 5;

   wxProgressDialog *progress = NULL;
   wxYield();
   wxStartTimer();
   wxBusyCursor busy;
   bool cancelling = false;

   int numWaveTracks;
   WaveTrack **waveTracks;
   tracks->GetWaveTracks(mExportSelection, &numWaveTracks, &waveTracks);



  
   Mixer *mixer = new Mixer(numWaveTracks, waveTracks,
                            tracks->GetTimeTrack(),
                            m_t0, m_t1,
                            info.channels, maxBlockLen, true,
                            mInRate, format);

   while(!cancelling) {
      sampleCount numSamples = mixer->Process(maxBlockLen);

      if (numSamples == 0)
         break;
      
      samplePtr mixed = mixer->GetBuffer();

      if (format == int16Sample)
         sf_writef_short(sf, (short *)mixed, numSamples);
      else
         sf_writef_float(sf, (float *)mixed, numSamples);

      if (!progress && wxGetElapsedTime(false) > 500) {

         wxString message;

         if (mExportSelection)
            message =
                wxString::
                Format(_("Exporting the selected audio as a %s file"),
                       (const char *) formatStr);
         else
            message =
                wxString::
                Format(_("Exporting the entire project as a %s file"),
                       (const char *) formatStr);

         progress =
             new wxProgressDialog(_("Export"),
                                  message,
                                  1000,
                                  parent,
                                  wxPD_CAN_ABORT |
                                  wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
      }
      if (progress) {
         int progressvalue = int (1000 * ((mixer->MixGetCurrentTime()-m_t0) /
                                          (m_t1-m_t0)));
         cancelling = !progress->Update(progressvalue);
      }
   }

   delete mixer;

   delete[] waveTracks;                            

   err = sf_close(sf);

   if (err) {
      char buffer[1000];
      sf_error_str(sf, buffer, 1000);
      wxMessageBox(wxString::Format
                   (_("Error (file may not have been written): %s"),
                    buffer));
   }

#ifdef __WXMAC__

   FSSpec spec;

   wxMacFilename2FSSpec(fName, &spec);

   FInfo finfo;
   if (FSpGetFInfo(&spec, &finfo) == noErr) {
      finfo.fdType = sf_header_mactype(mSoundFileFormat & SF_FORMAT_TYPEMASK);
      finfo.fdCreator = AUDACITY_CREATOR;

      FSpSetFInfo(&spec, &finfo);
   }
#endif

   if (progress)
      delete progress;

   return true;
}
예제 #8
0
//TODO-MB: wouldn't it make more sense to delete the time track after 'mix and render'?
bool MixAndRender(TrackList *tracks, TrackFactory *trackFactory,
                  double rate, sampleFormat format,
                  double startTime, double endTime,
                  WaveTrack **newLeft, WaveTrack **newRight)
{
   // This function was formerly known as "Quick Mix".
   WaveTrack **waveArray;
   Track *t;
   int numWaves = 0; /* number of wave tracks in the selection */
   int numMono = 0;  /* number of mono, centre-panned wave tracks in selection*/
   bool mono = false;   /* flag if output can be mono without loosing anything*/
   bool oneinput = false;  /* flag set to true if there is only one input track
                              (mono or stereo) */
   int w;

   TrackListIterator iter(tracks);
   SelectedTrackListOfKindIterator usefulIter(Track::Wave, tracks);
   // this only iterates tracks which are relevant to this function, i.e.
   // selected WaveTracks. The tracklist is (confusingly) the list of all
   // tracks in the project

   t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == Track::Wave) {
         numWaves++;
         float pan = ((WaveTrack*)t)->GetPan();
         if (t->GetChannel() == Track::MonoChannel && pan == 0)
            numMono++;
      }
      t = iter.Next();
   }

   if (numMono == numWaves)
      mono = true;

   /* the next loop will do two things at once:
    * 1. build an array of all the wave tracks were are trying to process
    * 2. determine when the set of WaveTracks starts and ends, in case we
    *    need to work out for ourselves when to start and stop rendering.
    */

   double mixStartTime = 0.0;    /* start time of first track to start */
   bool gotstart = false;  // flag indicates we have found a start time
   double mixEndTime = 0.0;   /* end time of last track to end */
   double tstart, tend;    // start and end times for one track.

   waveArray = new WaveTrack *[numWaves];
   w = 0;
   t = iter.First();

   while (t) {
      if (t->GetSelected() && t->GetKind() == Track::Wave) {
         waveArray[w++] = (WaveTrack *) t;
         tstart = t->GetStartTime();
         tend = t->GetEndTime();
         if (tend > mixEndTime)
            mixEndTime = tend;
         // try and get the start time. If the track is empty we will get 0,
         // which is ambiguous because it could just mean the track starts at
         // the beginning of the project, as well as empty track. The give-away
         // is that an empty track also ends at zero.

         if (tstart != tend) {
            // we don't get empty tracks here
            if (!gotstart) {
               // no previous start, use this one unconditionally
               mixStartTime = tstart;
               gotstart = true;
            } else if (tstart < mixStartTime)
               mixStartTime = tstart;  // have a start, only make it smaller
         }  // end if start and end are different
      }  // end if track is a selected WaveTrack.
      /** @TODO: could we not use a SelectedTrackListOfKindIterator here? */
      t = iter.Next();
   }

   /* create the destination track (new track) */
   if ((numWaves == 1) || ((numWaves == 2) && (usefulIter.First()->GetLink() != NULL)))
      oneinput = true;
   // only one input track (either 1 mono or one linked stereo pair)

   WaveTrack *mixLeft = trackFactory->NewWaveTrack(format, rate);
   if (oneinput)
      mixLeft->SetName(usefulIter.First()->GetName()); /* set name of output track to be the same as the sole input track */
   else
      mixLeft->SetName(_("Mix"));
   mixLeft->SetOffset(mixStartTime);
   WaveTrack *mixRight = 0;
   if (mono) {
      mixLeft->SetChannel(Track::MonoChannel);
   }
   else {
      mixRight = trackFactory->NewWaveTrack(format, rate);
      if (oneinput) {
         if (usefulIter.First()->GetLink() != NULL)   // we have linked track
            mixLeft->SetName(usefulIter.First()->GetLink()->GetName()); /* set name to match input track's right channel!*/
         else
            mixLeft->SetName(usefulIter.First()->GetName());   /* set name to that of sole input channel */
      }
      else
         mixRight->SetName(_("Mix"));
      mixLeft->SetChannel(Track::LeftChannel);
      mixRight->SetChannel(Track::RightChannel);
      mixRight->SetOffset(mixStartTime);
      mixLeft->SetLinked(true);
   }



   int maxBlockLen = mixLeft->GetIdealBlockSize();

   // If the caller didn't specify a time range, use the whole range in which
   // any input track had clips in it.
   if (startTime == endTime) {
      startTime = mixStartTime;
      endTime = mixEndTime;
   }

   Mixer *mixer = new Mixer(numWaves, waveArray,
                            Mixer::WarpOptions(tracks->GetTimeTrack()),
                            startTime, endTime, mono ? 1 : 2, maxBlockLen, false,
                            rate, format);

   ::wxSafeYield();
   ProgressDialog *progress = new ProgressDialog(_("Mix and Render"),
                                                 _("Mixing and rendering tracks"));

   int updateResult = eProgressSuccess;
   while(updateResult == eProgressSuccess) {
      sampleCount blockLen = mixer->Process(maxBlockLen);

      if (blockLen == 0)
         break;

      if (mono) {
         samplePtr buffer = mixer->GetBuffer();
         mixLeft->Append(buffer, format, blockLen);
      }
      else {
         samplePtr buffer;
         buffer = mixer->GetBuffer(0);
         mixLeft->Append(buffer, format, blockLen);
         buffer = mixer->GetBuffer(1);
         mixRight->Append(buffer, format, blockLen);
      }

      updateResult = progress->Update(mixer->MixGetCurrentTime() - startTime, endTime - startTime);
   }

   delete progress;

   mixLeft->Flush();
   if (!mono)
      mixRight->Flush();
   if (updateResult == eProgressCancelled || updateResult == eProgressFailed)
   {
      delete mixLeft;
      if (!mono)
         delete mixRight;
   } else {
      *newLeft = mixLeft;
      if (!mono)
         *newRight = mixRight;

#if 0
   int elapsedMS = wxGetElapsedTime();
   double elapsedTime = elapsedMS * 0.001;
   double maxTracks = totalTime / (elapsedTime / numWaves);

   // Note: these shouldn't be translated - they're for debugging
   // and profiling only.
   printf("      Tracks: %d\n", numWaves);
   printf("  Mix length: %f sec\n", totalTime);
   printf("Elapsed time: %f sec\n", elapsedTime);
   printf("Max number of tracks to mix in real time: %f\n", maxTracks);
#endif
   }

   delete[] waveArray;
   delete mixer;

   return (updateResult == eProgressSuccess || updateResult == eProgressStopped);
}
예제 #9
0
int ExportFFmpeg::Export(AudacityProject *project,
                       int channels, const wxString &fName,
                       bool selectionOnly, double t0, double t1, MixerSpec *mixerSpec, const Tags *metadata, int subformat)
{
   if (!CheckFFmpegPresence())
      return false;
   mChannels = channels;
   // subformat index may not correspond directly to fmts[] index, convert it
   mSubFormat = AdjustFormatIndex(subformat);
   if (channels > ExportFFmpegOptions::fmts[mSubFormat].maxchannels)
   {
      wxMessageBox(
         wxString::Format(
               _("Attempted to export %d channels, but maximum number of channels for selected output format is %d"),
               channels,
               ExportFFmpegOptions::fmts[mSubFormat].maxchannels),
            _("Error"));
      return false;
   }
   mName = fName;
   TrackList *tracks = project->GetTracks();
   bool ret = true;

   if (mSubFormat >= FMT_LAST) return false;

   wxString shortname(ExportFFmpegOptions::fmts[mSubFormat].shortname);
   if (mSubFormat == FMT_OTHER)
      shortname = gPrefs->Read(wxT("/FileFormats/FFmpegFormat"),wxT("matroska"));
   ret = Init(shortname.mb_str(),project, metadata, subformat);

   if (!ret) return false;

   int pcmBufferSize = 1024;
   int numWaveTracks;
   WaveTrack **waveTracks;
   tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks);
   Mixer *mixer = CreateMixer(numWaveTracks, waveTracks,
      tracks->GetTimeTrack(),
      t0, t1,
      channels, pcmBufferSize, true,
      mSampleRate, int16Sample, true, mixerSpec);
   delete[] waveTracks;

   int updateResult = eProgressSuccess;
   {
      ProgressDialog progress(wxFileName(fName).GetName(),
         selectionOnly ?
         wxString::Format(_("Exporting selected audio as %s"), ExportFFmpegOptions::fmts[mSubFormat].description) :
         wxString::Format(_("Exporting entire file as %s"), ExportFFmpegOptions::fmts[mSubFormat].description));

      while (updateResult == eProgressSuccess) {
         sampleCount pcmNumSamples = mixer->Process(pcmBufferSize);

         if (pcmNumSamples == 0)
            break;

         short *pcmBuffer = (short *)mixer->GetBuffer();

         EncodeAudioFrame(pcmBuffer, (pcmNumSamples)*sizeof(int16_t)*mChannels);

         updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0);
      }
   }

   delete mixer;

   Finalize();

   return updateResult;
}
예제 #10
0
bool ExportCL(AudacityProject *project, bool stereo, wxString fName,
              bool selectionOnly, double t0, double t1)
{
   int rate = int(project->GetRate() + 0.5);
   wxWindow *parent = project;
   TrackList *tracks = project->GetTracks();
   
   wxString command = gPrefs->Read("/FileFormats/ExternalProgramExportCommand", "lame - '%f'");
   command.Replace("%f", fName);

   /* establish parameters */
   int channels = stereo ? 2 : 1;
   unsigned long totalSamples = (unsigned long)((t1 - t0) * rate + 0.5);
   unsigned long sampleBytes = totalSamples * channels * SAMPLE_SIZE(int16Sample);
   double timeStep = 10.0;      // write in blocks of 10 secs

   /* fill up the wav header */
   wav_header header;
   header.riffID[0] = 'R';
   header.riffID[1] = 'I';
   header.riffID[2] = 'F';
   header.riffID[3] = 'F';
   header.riffType[0] = 'W';
   header.riffType[1] = 'A';
   header.riffType[2] = 'V';
   header.riffType[3] = 'E';
   header.lenAfterRiff = sampleBytes + 32;

   header.fmtID[0]  = 'f';
   header.fmtID[1]  = 'm';
   header.fmtID[2]  = 't';
   header.fmtID[3]  = ' ';
   header.formatChunkLen = 16;
   header.formatTag      = 1;
   header.channels       = channels;
   header.sampleRate     = rate;
   header.bitsPerSample  = SAMPLE_SIZE(int16Sample) * 8;
   header.blockAlign     = header.bitsPerSample * header.channels;
   header.avgBytesPerSec = header.sampleRate * header.blockAlign;

   header.dataID[0] = 'd';
   header.dataID[1] = 'a';
   header.dataID[2] = 't';
   header.dataID[3] = 'a';
   header.dataLen   = sampleBytes;

   FILE *pipe = popen(command.c_str(), "w");

   /* write the header */

   fwrite( &header, sizeof(wav_header), 1, pipe );

   //sampleCount maxSamples = int (timeStep * rate + 0.5);

   wxProgressDialog *progress = NULL;
   wxYield();
   wxStartTimer();
   wxBusyCursor busy;
   bool cancelling = false;

   double t = t0;

   while (t < t1 && !cancelling) {

      double deltat = timeStep;
      if (t + deltat > t1)
         deltat = t1 - t;

      sampleCount numSamples = int (deltat * rate + 0.5);

      Mixer *mixer = new Mixer(channels, numSamples, true, rate, int16Sample);
      wxASSERT(mixer);
      mixer->Clear();

      char *buffer = new char[numSamples * SAMPLE_SIZE(int16Sample) * channels];
      wxASSERT(buffer);

      TrackListIterator iter(tracks);
      VTrack *tr = iter.First();
      while (tr) {
         if (tr->GetKind() == VTrack::Wave) {
            if (tr->GetSelected() || !selectionOnly) {
               if (tr->GetChannel() == VTrack::MonoChannel)
                  mixer->MixMono((WaveTrack *) tr, t, t + deltat);
               if (tr->GetChannel() == VTrack::LeftChannel)
                  mixer->MixLeft((WaveTrack *) tr, t, t + deltat);
               if (tr->GetChannel() == VTrack::RightChannel)
                  mixer->MixRight((WaveTrack *) tr, t, t + deltat);
            }
         }
         tr = iter.Next();
      }

      samplePtr mixed = mixer->GetBuffer();

      // Byte-swapping is neccesary on big-endian machines, since
      // WAV files are little-endian
#if wxBYTE_ORDER == wxBIG_ENDIAN
      {
         short *buffer = (short*)mixed;
         for( int i = 0; i < numSamples; i++ )
            buffer[i] = wxINT16_SWAP_ON_BE(buffer[i]);
      }
#endif

      fwrite( mixed, numSamples * channels * SAMPLE_SIZE(int16Sample), 1, pipe );

      t += deltat;

      if (!progress && wxGetElapsedTime(false) > 500) {

         wxString message;

         if (selectionOnly)
            message = "Exporting the selected audio using command-line encoder";
         else
            message = "Exporting the entire project using command-line encoder";

         progress =
             new wxProgressDialog("Export",
                                  message,
                                  1000,
                                  parent,
                                  wxPD_CAN_ABORT |
                                  wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
      }
      if (progress) {
         cancelling =
             !progress->Update(int (((t - t0) * 1000) / (t1 - t0) + 0.5));
      }

      delete mixer;
      delete[]buffer;
   }

   pclose( pipe );

   if(progress)
      delete progress;
   return true;
}
예제 #11
0
bool ExportOGG(AudacityProject *project,
               bool stereo, wxString fName,
               bool selectionOnly, double t0, double t1)
{
    double    rate    = project->GetRate();
    wxWindow  *parent = project;
    TrackList *tracks = project->GetTracks();
    double    quality = (gPrefs->Read("/FileFormats/OggExportQuality", 50)/(float)100.0);

    wxLogNull logNo;            // temporarily disable wxWindows error messages
    bool      cancelling = false;
    int       eos = 0;

    wxFFile outFile(fName, "wb");

    if(!outFile.IsOpened()) {
        wxMessageBox(_("Unable to open target file for writing"));
        return false;
    }

    // All the Ogg and Vorbis encoding data
    ogg_stream_state stream;
    ogg_page         page;
    ogg_packet       packet;

    vorbis_info      info;
    vorbis_comment   comment;
    vorbis_dsp_state dsp;
    vorbis_block     block;

    // Encoding setup
    vorbis_info_init(&info);
    vorbis_encode_init_vbr(&info, stereo ? 2 : 1, int(rate + 0.5), quality);

    vorbis_comment_init(&comment);
    // If we wanted to add comments, we would do it here

    // Set up analysis state and auxiliary encoding storage
    vorbis_analysis_init(&dsp, &info);
    vorbis_block_init(&dsp, &block);

    // Set up packet->stream encoder.  According to encoder example,
    // a random serial number makes it more likely that you can make
    // chained streams with concatenation.
    srand(time(NULL));
    ogg_stream_init(&stream, rand());

    // First we need to write the required headers:
    //    1. The Ogg bitstream header, which contains codec setup params
    //    2. The Vorbis comment header
    //    3. The bitstream codebook.
    //
    // After we create those our responsibility is complete, libvorbis will
    // take care of any other ogg bistream constraints (again, according
    // to the example encoder source)
    ogg_packet bitstream_header;
    ogg_packet comment_header;
    ogg_packet codebook_header;

    vorbis_analysis_headerout(&dsp, &comment, &bitstream_header, &comment_header,
                              &codebook_header);

    // Place these headers into the stream
    ogg_stream_packetin(&stream, &bitstream_header);
    ogg_stream_packetin(&stream, &comment_header);
    ogg_stream_packetin(&stream, &codebook_header);

    // Flushing these headers now guarentees that audio data will
    // start on a new page, which apparently makes streaming easier
    while(ogg_stream_flush(&stream, &page))
    {
        outFile.Write(page.header, page.header_len);
        outFile.Write(page.body, page.body_len);
    }

    wxProgressDialog *progress = NULL;

    wxYield();
    wxStartTimer();

    int numWaveTracks;
    WaveTrack **waveTracks;
    tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks);
    Mixer *mixer = new Mixer(numWaveTracks, waveTracks,
                             tracks->GetTimeTrack(),
                             t0, t1,
                             stereo? 2: 1, SAMPLES_PER_RUN, false,
                             rate, floatSample);

    while(!cancelling && !eos) {
        float **vorbis_buffer = vorbis_analysis_buffer(&dsp, SAMPLES_PER_RUN);
        sampleCount samplesThisRun = mixer->Process(SAMPLES_PER_RUN);

        if (samplesThisRun == 0) {
            // Tell the library that we wrote 0 bytes - signalling the end.
            vorbis_analysis_wrote(&dsp, 0);
        }
        else {

            float *left = (float *)mixer->GetBuffer(0);
            memcpy(vorbis_buffer[0], left, sizeof(float)*SAMPLES_PER_RUN);

            if(stereo) {
                float *right = (float *)mixer->GetBuffer(1);
                memcpy(vorbis_buffer[1], right, sizeof(float)*SAMPLES_PER_RUN);
            }

            // tell the encoder how many samples we have
            vorbis_analysis_wrote(&dsp, samplesThisRun);
        }

        // I don't understand what this call does, so here is the comment
        // from the example, verbatim:
        //
        //    vorbis does some data preanalysis, then divvies up blocks
        //    for more involved (potentially parallel) processing. Get
        //    a single block for encoding now
        while(vorbis_analysis_blockout(&dsp, &block) == 1) {

            // analysis, assume we want to use bitrate management
            vorbis_analysis(&block, NULL);
            vorbis_bitrate_addblock(&block);

            while(vorbis_bitrate_flushpacket(&dsp, &packet)) {

                // add the packet to the bitstream
                ogg_stream_packetin(&stream, &packet);

                // From vorbis-tools-1.0/oggenc/encode.c:
                //   If we've gone over a page boundary, we can do actual output,
                //   so do so (for however many pages are available).

                while (!eos) {
                    int result = ogg_stream_pageout(&stream, &page);
                    if (!result)
                        break;

                    outFile.Write(page.header, page.header_len);
                    outFile.Write(page.body, page.body_len);

                    if (ogg_page_eos(&page))
                        eos = 1;
                }
            }
        }

        if(progress) {
            int progressvalue = int (1000 * ((mixer->MixGetCurrentTime()-t0) /
                                             (t1-t0)));
            cancelling = !progress->Update(progressvalue);
        }
        else if(wxGetElapsedTime(false) > 500) {

            wxString message = selectionOnly ?
                               _("Exporting the selected audio as Ogg Vorbis") :
                               _("Exporting the entire project as Ogg Vorbis");

            progress = new wxProgressDialog(
                _("Export"),
                message,
                1000,
                parent,
                wxPD_CAN_ABORT | wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
        }
    }

    delete mixer;

    ogg_stream_clear(&stream);

    vorbis_block_clear(&block);
    vorbis_dsp_clear(&dsp);
    vorbis_info_clear(&info);

    outFile.Close();

    if(progress)
        delete progress;

    return true;
}
예제 #12
0
int ExportOGG::Export(AudacityProject *project,
                       int numChannels,
                       wxString fName,
                       bool selectionOnly,
                       double t0,
                       double t1,
                       MixerSpec *mixerSpec,
                       Tags *metadata,
                       int WXUNUSED(subformat))
{
   double    rate    = project->GetRate();
   TrackList *tracks = project->GetTracks();
   double    quality = (gPrefs->Read(wxT("/FileFormats/OggExportQuality"), 50)/(float)100.0);

   wxLogNull logNo;            // temporarily disable wxWidgets error messages
   int updateResult = eProgressSuccess;
   int       eos = 0;

   FileIO outFile(fName, FileIO::Output);

   if (!outFile.IsOpened()) {
      wxMessageBox(_("Unable to open target file for writing"));
      return false;
   }

   // All the Ogg and Vorbis encoding data
   ogg_stream_state stream;
   ogg_page         page;
   ogg_packet       packet;

   vorbis_info      info;
   vorbis_comment   comment;
   vorbis_dsp_state dsp;
   vorbis_block     block;

   // Encoding setup
   vorbis_info_init(&info);
   vorbis_encode_init_vbr(&info, numChannels, int(rate + 0.5), quality);

   // Retrieve tags
   if (!FillComment(project, &comment, metadata)) {
      return false;
   }

   // Set up analysis state and auxiliary encoding storage
   vorbis_analysis_init(&dsp, &info);
   vorbis_block_init(&dsp, &block);

   // Set up packet->stream encoder.  According to encoder example,
   // a random serial number makes it more likely that you can make
   // chained streams with concatenation.
   srand(time(NULL));
   ogg_stream_init(&stream, rand());

   // First we need to write the required headers:
   //    1. The Ogg bitstream header, which contains codec setup params
   //    2. The Vorbis comment header
   //    3. The bitstream codebook.
   //
   // After we create those our responsibility is complete, libvorbis will
   // take care of any other ogg bistream constraints (again, according
   // to the example encoder source)
   ogg_packet bitstream_header;
   ogg_packet comment_header;
   ogg_packet codebook_header;

   vorbis_analysis_headerout(&dsp, &comment, &bitstream_header, &comment_header,
         &codebook_header);

   // Place these headers into the stream
   ogg_stream_packetin(&stream, &bitstream_header);
   ogg_stream_packetin(&stream, &comment_header);
   ogg_stream_packetin(&stream, &codebook_header);

   // Flushing these headers now guarentees that audio data will
   // start on a NEW page, which apparently makes streaming easier
   while (ogg_stream_flush(&stream, &page)) {
      outFile.Write(page.header, page.header_len);
      outFile.Write(page.body, page.body_len);
   }

   int numWaveTracks;
   WaveTrack **waveTracks;
   tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks);
   Mixer *mixer = CreateMixer(numWaveTracks, waveTracks,
                            tracks->GetTimeTrack(),
                            t0, t1,
                            numChannels, SAMPLES_PER_RUN, false,
                            rate, floatSample, true, mixerSpec);
   delete [] waveTracks;

   ProgressDialog *progress = new ProgressDialog(wxFileName(fName).GetName(),
      selectionOnly ?
      _("Exporting the selected audio as Ogg Vorbis") :
      _("Exporting the entire project as Ogg Vorbis"));

   while (updateResult == eProgressSuccess && !eos) {
      float **vorbis_buffer = vorbis_analysis_buffer(&dsp, SAMPLES_PER_RUN);
      sampleCount samplesThisRun = mixer->Process(SAMPLES_PER_RUN);

      if (samplesThisRun == 0) {
         // Tell the library that we wrote 0 bytes - signalling the end.
         vorbis_analysis_wrote(&dsp, 0);
      }
      else {

         for (int i = 0; i < numChannels; i++) {
            float *temp = (float *)mixer->GetBuffer(i);
            memcpy(vorbis_buffer[i], temp, sizeof(float)*SAMPLES_PER_RUN);
         }

         // tell the encoder how many samples we have
         vorbis_analysis_wrote(&dsp, samplesThisRun);
      }

      // I don't understand what this call does, so here is the comment
      // from the example, verbatim:
      //
      //    vorbis does some data preanalysis, then divvies up blocks
      //    for more involved (potentially parallel) processing. Get
      //    a single block for encoding now
      while (vorbis_analysis_blockout(&dsp, &block) == 1) {

         // analysis, assume we want to use bitrate management
         vorbis_analysis(&block, NULL);
         vorbis_bitrate_addblock(&block);

         while (vorbis_bitrate_flushpacket(&dsp, &packet)) {

            // add the packet to the bitstream
            ogg_stream_packetin(&stream, &packet);

            // From vorbis-tools-1.0/oggenc/encode.c:
            //   If we've gone over a page boundary, we can do actual output,
            //   so do so (for however many pages are available).

            while (!eos) {
               int result = ogg_stream_pageout(&stream, &page);
               if (!result) {
                  break;
               }

               outFile.Write(page.header, page.header_len);
               outFile.Write(page.body, page.body_len);

               if (ogg_page_eos(&page)) {
                  eos = 1;
               }
            }
         }
      }

      updateResult = progress->Update(mixer->MixGetCurrentTime()-t0, t1-t0);
   }

   delete progress;;

   delete mixer;

   ogg_stream_clear(&stream);

   vorbis_block_clear(&block);
   vorbis_dsp_clear(&dsp);
   vorbis_info_clear(&info);
   vorbis_comment_clear(&comment);

   outFile.Close();

   return updateResult;
}
예제 #13
0
bool ExportMP3(AudacityProject *project,
               bool stereo, wxString fName,
               bool selectionOnly, double t0, double t1)
{
   double rate = project->GetRate();
   wxWindow *parent = project;
   TrackList *tracks = project->GetTracks();

   wxLogNull logNo;             /* temporarily disable wxWindows error messages */

   bool success = GetMP3Exporter()->FindLibrary(parent);
   
   if (!success)
      return false;

   success = GetMP3Exporter()->LoadLibrary();
   if (!success) {
      wxMessageBox(_("Could not open MP3 encoding library!"));
      gPrefs->Write("/MP3/MP3LibPath", wxString(""));

      return false;
   }

   if(!GetMP3Exporter()->ValidLibraryLoaded()) {
      wxMessageBox(_("Not a valid or supported MP3 encoding library!"));      
      gPrefs->Write("/MP3/MP3LibPath", wxString(""));
      
      return false;
   }
   
   /* Open file for writing */

   wxFFile outFile(fName, "wb");
   if (!outFile.IsOpened()) {
      wxMessageBox(_("Unable to open target file for writing"));
      return false;
   }
   
   /* Put ID3 tags at beginning of file */
   
   Tags *tags = project->GetTags();
   if (!tags->ShowEditDialog(project, _("Edit the ID3 tags for the MP3 file")))
      return false;  // used selected "cancel"

   char *id3buffer;
   int id3len;
   bool endOfFile;
   id3len = tags->ExportID3(&id3buffer, &endOfFile);
   if (!endOfFile)
     outFile.Write(id3buffer, id3len);

   /* Export MP3 using DLL */

   long bitrate = gPrefs->Read("/FileFormats/MP3Bitrate", 128);
   GetMP3Exporter()->SetBitrate(bitrate);

   sampleCount inSamples = GetMP3Exporter()->InitializeStream(stereo ? 2 : 1, int(rate + 0.5));
   double timeStep =  (double)inSamples / rate;
   double t = t0;

   wxProgressDialog *progress = NULL;
   wxYield();
   wxStartTimer();
   wxBusyCursor busy;
   bool cancelling = false;
   long bytes;


   int bufferSize = GetMP3Exporter()->GetOutBufferSize();
   unsigned char *buffer = new unsigned char[bufferSize];
   wxASSERT(buffer);

   while (t < t1 && !cancelling) {

      double deltat = timeStep;
      bool lastFrame = false;
      sampleCount numSamples = inSamples;

      if (t + deltat > t1) {
         lastFrame = true;
         deltat = t1 - t;
         numSamples = int(deltat * rate + 0.5);
      }


      Mixer *mixer = new Mixer(stereo ? 2 : 1, numSamples, true,
                               rate, int16Sample);
      wxASSERT(mixer);
      mixer->Clear();


      TrackListIterator iter(tracks);
      VTrack *tr = iter.First();
      while (tr) {
         if (tr->GetKind() == VTrack::Wave) {
            if (tr->GetSelected() || !selectionOnly) {
               if (tr->GetChannel() == VTrack::MonoChannel)
                  mixer->MixMono((WaveTrack *) tr, t, t + deltat);
               else if (tr->GetChannel() == VTrack::LeftChannel)
                  mixer->MixLeft((WaveTrack *) tr, t, t + deltat);
               else if (tr->GetChannel() == VTrack::RightChannel)
                  mixer->MixRight((WaveTrack *) tr, t, t + deltat);
            }
         }
         tr = iter.Next();
      }
      
      short *mixed = (short *)mixer->GetBuffer();

      if(lastFrame)
         bytes = GetMP3Exporter()->EncodeRemainder(mixed, numSamples, buffer);
      else
         bytes = GetMP3Exporter()->EncodeBuffer(mixed, buffer);

      outFile.Write(buffer, bytes);

      t += deltat;

      if (!progress && wxGetElapsedTime(false) > 500) {

         wxString message;

         if (selectionOnly)
            message =
                wxString::Format(_("Exporting the selected audio as an mp3"));
         else
            message =
                wxString::Format(_("Exporting the entire project as an mp3"));

         progress =
             new wxProgressDialog(_("Export"),
                                  message,
                                  1000,
                                  parent,
                                  wxPD_CAN_ABORT |
                                  wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
      }

      if (progress) {
         cancelling =
             !progress->Update(int (((t - t0) * 1000) / (t1 - t0) + 0.5));
      }

      delete mixer;

   }

   bytes = GetMP3Exporter()->FinishStream(buffer);

   if (bytes)
      outFile.Write(buffer, bytes);
   
   /* Write ID3 tag if it was supposed to be at the end of the file */
   
   if (endOfFile)
      outFile.Write(id3buffer, id3len);
   delete[] id3buffer;

   /* Close file */
   
   outFile.Close();
      
   /* MacOS: set the file type/creator so that the OS knows it's an MP3
      file which was created by Audacity */
      
#ifdef __WXMAC__
   FSSpec spec;
   wxMacFilename2FSSpec(fName, &spec);
   FInfo finfo;
   if (FSpGetFInfo(&spec, &finfo) == noErr) {
      finfo.fdType = 'MP3 ';
      finfo.fdCreator = AUDACITY_CREATOR;

      FSpSetFInfo(&spec, &finfo);
   }
#endif

   if (progress)
      delete progress;

   delete[]buffer;
   
   return true;
}
예제 #14
0
bool ExportCL(AudacityProject *project, bool stereo, wxString fName,
              bool selectionOnly, double t0, double t1, MixerSpec *mixerSpec)
{
   int rate = int(project->GetRate() + 0.5);
   wxWindow *parent = project;
   TrackList *tracks = project->GetTracks();
   
   wxString command = gPrefs->Read(wxT("/FileFormats/ExternalProgramExportCommand"), wxT("lame - '%f'"));
   command.Replace(wxT("%f"), fName);

   /* establish parameters */
   int channels = stereo ? 2 : 1;
   unsigned long totalSamples = (unsigned long)((t1 - t0) * rate + 0.5);
   unsigned long sampleBytes = totalSamples * channels * SAMPLE_SIZE(int16Sample);

   /* fill up the wav header */
   wav_header header;
   header.riffID[0] = 'R';
   header.riffID[1] = 'I';
   header.riffID[2] = 'F';
   header.riffID[3] = 'F';
   header.riffType[0] = 'W';
   header.riffType[1] = 'A';
   header.riffType[2] = 'V';
   header.riffType[3] = 'E';
   header.lenAfterRiff = sampleBytes + 32;

   header.fmtID[0]  = 'f';
   header.fmtID[1]  = 'm';
   header.fmtID[2]  = 't';
   header.fmtID[3]  = ' ';
   header.formatChunkLen = 16;
   header.formatTag      = 1;
   header.channels       = channels;
   header.sampleRate     = rate;
   header.bitsPerSample  = SAMPLE_SIZE(int16Sample) * 8;
   header.blockAlign     = header.bitsPerSample * header.channels;
   header.avgBytesPerSec = header.sampleRate * header.blockAlign;

   header.dataID[0] = 'd';
   header.dataID[1] = 'a';
   header.dataID[2] = 't';
   header.dataID[3] = 'a';
   header.dataLen   = sampleBytes;

   FILE *pipe = popen(OSFILENAME(command), "w");

   /* write the header */

   fwrite( &header, sizeof(wav_header), 1, pipe );

   sampleCount maxBlockLen = 44100 * 5;

   bool cancelling = false;

   int numWaveTracks;
   WaveTrack **waveTracks;
   tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks);
   Mixer *mixer = new Mixer(numWaveTracks, waveTracks,
                            tracks->GetTimeTrack(),
                            t0, t1,
                            channels, maxBlockLen, true,
                            rate, int16Sample, true, mixerSpec);

   GetActiveProject()->ProgressShow(_("Export"),
      selectionOnly ?
      _("Exporting the selected audio using command-line encoder") :
      _("Exporting the entire project using command-line encoder"));

   while(!cancelling) {
      sampleCount numSamples = mixer->Process(maxBlockLen);

      if (numSamples == 0)
         break;
      
      samplePtr mixed = mixer->GetBuffer();

      char *buffer = new char[numSamples * SAMPLE_SIZE(int16Sample) * channels];
      wxASSERT(buffer);

      // Byte-swapping is neccesary on big-endian machines, since
      // WAV files are little-endian
#if wxBYTE_ORDER == wxBIG_ENDIAN
      {
         short *buffer = (short*)mixed;
         for( int i = 0; i < numSamples; i++ )
            buffer[i] = wxINT16_SWAP_ON_BE(buffer[i]);
      }
#endif

      fwrite( mixed, numSamples * channels * SAMPLE_SIZE(int16Sample), 1, pipe );

      int progressvalue = int (1000 * ((mixer->MixGetCurrentTime()-t0) /
                                       (t1-t0)));
      cancelling = !GetActiveProject()->ProgressUpdate(progressvalue);

      delete[]buffer;
   }
   GetActiveProject()->ProgressHide();

   delete mixer;

   pclose( pipe );

   return true;
}
예제 #15
0
bool ExportPCM(AudacityProject *project,
               bool stereo, wxString fName,
               bool selectionOnly, double t0, double t1)
{
   double       rate = project->GetRate();
   wxWindow    *parent = project;
   TrackList   *tracks = project->GetTracks();
   int          format = ReadExportFormatPref();
   int          formatBits = ReadExportFormatBitsPref();
   wxString     formatStr;
   SF_INFO      info;
   SNDFILE     *sf;
   int          err;

   formatStr = sf_header_name(format & SF_FORMAT_TYPEMASK);

   // Use libsndfile to export file

   info.samplerate = (unsigned int)(rate + 0.5);
   info.samples = (unsigned int)((t1 - t0)*rate + 0.5);
   info.channels = stereo? 2: 1;
   info.pcmbitwidth = formatBits;
   info.format = format;
   info.sections = 1;
   info.seekable = 0;

   // If we can't export exactly the format they requested,
   // try the default format for that header type, and try
   // 16-bit samples.
   if (!sf_format_check(&info))
      info.format = (info.format & SF_FORMAT_TYPEMASK);
   if (!sf_format_check(&info))
      info.pcmbitwidth = 16;
   if (!sf_format_check(&info)) {
      wxMessageBox(_("Cannot export audio in this format."));
      return false;
   }

   sf = sf_open_write((const char *)fName, &info);
   if (!sf) {
      wxMessageBox(wxString::Format(_("Cannot export audio to %s"),
                                    (const char *)fName));
      return false;
   }

   double timeStep = 10.0;      // write in blocks of 10 secs

   wxProgressDialog *progress = NULL;
   wxYield();
   wxStartTimer();
   wxBusyCursor busy;
   bool cancelling = false;

   double t = t0;

   while (t < t1 && !cancelling) {

      double deltat = timeStep;
      if (t + deltat > t1)
         deltat = t1 - t;

      sampleCount numSamples = int (deltat * rate + 0.5);

      Mixer *mixer = new Mixer(stereo ? 2 : 1, numSamples, true, rate);
      wxASSERT(mixer);
      mixer->Clear();

      TrackListIterator iter(tracks);
      VTrack *tr = iter.First();
      while (tr) {
         if (tr->GetKind() == VTrack::Wave) {
            if (tr->GetSelected() || !selectionOnly) {
               if (tr->GetChannel() == VTrack::MonoChannel)
                  mixer->MixMono((WaveTrack *) tr, t, t + deltat);
               if (tr->GetChannel() == VTrack::LeftChannel)
                  mixer->MixLeft((WaveTrack *) tr, t, t + deltat);
               if (tr->GetChannel() == VTrack::RightChannel)
                  mixer->MixRight((WaveTrack *) tr, t, t + deltat);
            }
         }
         tr = iter.Next();
      }

      sampleType *mixed = mixer->GetBuffer();

      sf_writef_short(sf, mixed, numSamples);

      t += deltat;

      if (!progress && wxGetElapsedTime(false) > 500) {

         wxString message;

         if (selectionOnly)
            message =
                wxString::
                Format(_("Exporting the selected audio as a %s file"),
                       (const char *) formatStr);
         else
            message =
                wxString::
                Format(_("Exporting the entire project as a %s file"),
                       (const char *) formatStr);

         progress =
             new wxProgressDialog(_("Export"),
                                  message,
                                  1000,
                                  parent,
                                  wxPD_CAN_ABORT |
                                  wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
      }
      if (progress) {
         cancelling =
             !progress->Update(int (((t - t0) * 1000) / (t1 - t0) + 0.5));
      }

      delete mixer;
   }

   err = sf_close(sf);

   if (err) {
      char buffer[1000];
      sf_error_str(sf, buffer, 1000);
      wxMessageBox(wxString::Format
                   (_("Error (file may not have been written): %s"),
                    buffer));
   }

#ifdef __WXMAC__

   FSSpec spec;

   wxMacFilename2FSSpec(fName, &spec);

   FInfo finfo;
   if (FSpGetFInfo(&spec, &finfo) == noErr) {
      finfo.fdType = sf_header_mactype(format & SF_FORMAT_TYPEMASK);
      finfo.fdCreator = AUDACITY_CREATOR;

      FSpSetFInfo(&spec, &finfo);
   }
#endif

   if (progress)
      delete progress;

   return true;
}
예제 #16
0
void AudioIO::FillBuffers()
{
   unsigned int numEmpty = 0;
   unsigned int i;
   
   // Playback buffers

   for(i=0; i<mNumOutBuffers; i++) {
      if (mOutBuffer[i].ID == 0)
         numEmpty++;
   }
   
   if (numEmpty > (mNumOutBuffers/2)) {
      sampleCount block = numEmpty * mBufferSize;   
      double deltat = block / mRate;
      if (mT + deltat > mT1) {
         deltat = mT1 - mT;
         if(deltat < 0.0) return;
         block = (sampleCount)(deltat * mRate + 0.5);
      }
      
      Mixer *mixer = new Mixer(mNumOutChannels, block, true,
                               mRate, mFormat);
      mixer->UseVolumeSlider(mProject->GetControlToolBar());

      mixer->Clear();

      TrackListIterator iter2(mTracks);
      int numSolo = 0;
      Track *vt = iter2.First();
      while (vt) {
         if (vt->GetKind() == Track::Wave && vt->GetSolo())
            numSolo++;
         vt = iter2.Next();
      }

      TrackListIterator iter(mTracks);
      vt = iter.First();
      while (vt) {
         if (vt->GetKind() == Track::Wave) {      

            Track *mt = vt;
         
            // We want to extract mute and solo information from
            // the top of the two tracks if they're linked
            // (i.e. a stereo pair only has one set of mute/solo buttons)
            Track *partner = mTracks->GetLink(vt);
            if (partner && !vt->GetLinked())
               mt = partner;
            else
               mt = vt;

            // Cut if somebody else is soloing
            if (numSolo>0 && !mt->GetSolo()) {
               vt = iter.Next();
               continue;
            }
            
            // Cut if we're muted (unless we're soloing)
            if (mt->GetMute() && !mt->GetSolo()) {
               vt = iter.Next();
               continue;
            }

            WaveTrack *t = (WaveTrack *) vt;
            
            switch (t->GetChannel()) {
            case Track::LeftChannel:
               mixer->MixLeft(t, mT, mT + deltat);
               break;
            case Track::RightChannel:
               mixer->MixRight(t, mT, mT + deltat);
               break;
            case Track::MonoChannel:
               mixer->MixMono(t, mT, mT + deltat);
               break;
            }
         }

         vt = iter.Next();
      }     
   
      // Copy the mixed samples into the buffers

      samplePtr outbytes = mixer->GetBuffer();   

      for(i=0; i<mNumOutBuffers && block>0; i++)
         if (mOutBuffer[i].ID == 0) {
            sampleCount count;
            if (block > mBufferSize)
               count = mBufferSize;
            else
               count = block;
            
            memcpy(mOutBuffer[i].data, outbytes,
                   count*mNumOutChannels*SAMPLE_SIZE(mFormat));
            block -= count;
            outbytes += (count*mNumOutChannels*SAMPLE_SIZE(mFormat));
            mOutBuffer[i].len = count;
            mOutBuffer[i].ID = mOutID;
            mOutID++;
         }

      delete mixer;

      mT += deltat;
   }
   
   // Recording buffers
   
   unsigned int numFull = 0;
   unsigned int f, c; // loop counters
   sampleCount flatLen;
      
   for(i=0; i<mNumInBuffers; i++) {
      if (mInBuffer[i].ID != 0)
         numFull++;
   }
   
   if (numFull > 8) {
   
      samplePtr *flat = new samplePtr[mNumInChannels];
      for(i=0; i<mNumInChannels; i++)
         flat[i] = NewSamples(numFull * mBufferSize, mFormat);
      
      flatLen = 0;
      for(f=0; f<numFull; f++) {
         int minID = mInID+1;
         int minIndex = 0;
         for(i=0; i<mNumInBuffers; i++)
            if (mInBuffer[i].ID > 0 &&
                mInBuffer[i].ID < minID) {
               minIndex = i;
               minID = mInBuffer[i].ID;
            }

         switch(mFormat) {
         case floatSample:
            int j;
            for(j=0; j<mInBuffer[minIndex].len; j++)
               for(c=0; c<mNumInChannels; c++) {
                  ((float *)flat[c])[flatLen+j] =
                     ((float *)mInBuffer[minIndex].data)[j*mNumInChannels + c];
               }
            break;
         default:
            wxASSERT(0);
         }

         flatLen += mInBuffer[minIndex].len;
         mInBuffer[minIndex].ID = 0;
      }
      
      for(i=0; i<mNumInChannels; i++)
         mInTracks[i]->Append(flat[i], mFormat, flatLen);

      for(i=0; i<mNumInChannels; i++)
         DeleteSamples(flat[i]);
      delete[] flat;

      mProject->RedrawProject();
   }
}