Пример #1
0
bool LOS::importMidi(const QString name, bool merge)/*{{{*/
{
    bool popenFlag;
    FILE* fp = fileOpen(this, name, QString(".mid"), "r", popenFlag);
    if (fp == 0)
        return true;
    MidiFile mf(fp);
    bool rv = mf.read();
    popenFlag ? pclose(fp) : fclose(fp);
    if (rv)
    {
        QString s(tr("reading midifile\n  "));
        s += name;
        s += tr("\nfailed: ");
        s += mf.error();
        QMessageBox::critical(this, QString("LOS"), s);
        return rv;
    }
    //
    //  evaluate song Type (GM, XG, GS, unknown)
    //
    MType t = song->mtype();
    if (!merge)
    {
        t = mf.mtype();
        song->setMType(t);
    }
    MidiInstrument* instr = 0;
    for (iMidiInstrument i = midiInstruments.begin(); i != midiInstruments.end(); ++i)
    {
        MidiInstrument* mi = *i;
        if ((mi->iname() == "GM" && ((t == MT_UNKNOWN) || (t == MT_GM)))
                || ((mi->iname() == "GS") && (t == MT_GS))
                || ((mi->iname() == "XG") && (t == MT_XG)))
        {
            instr = mi;
            break;
        }
    }
    if (instr == 0)
    {
        // the standard instrument files (GM, GS, XG) must be present
        printf("no instrument, type %d\n", t);
        return true;
        //abort();
    }

    MidiFileTrackList* etl = mf.trackList();
    int division = mf.division();

    //
    // create MidiTrack and copy events to ->events()
    //    - combine note on/off events
    //    - calculate tick value for internal resolution
    //
    int mPort = getFreeMidiPort();
    for (iMidiFileTrack t = etl->begin(); t != etl->end(); ++t)
    {
        MPEventList* el = &((*t)->events);
        if (el->empty())
            continue;
        //
        // if we split the track, SYSEX and META events go into
        // the first target track

        bool first = true;
        // somewhat silly and slooow:
        QList<QPair<int, int> > eventChannelList;
        if(mPort >= 0 && mPort < MIDI_PORTS)
        {
            for (int channel = 0; channel < MIDI_CHANNELS; ++channel)
            {
                //
                // check if there are any events for port/channel in track:
                //
                iMPEvent i;
                for (i = el->begin(); i != el->end(); ++i)
                {
                    MidiPlayEvent ev = *i;
                    if (ev.type() != ME_SYSEX && ev.type() != ME_META && ev.channel() == channel)
                        break;
                }
                if (i == el->end())
                    continue;
                MidiTrack* track = new MidiTrack();
                track->setDefaultName();
                track->setMasterFlag(true);

                track->setOutChannel(channel);
                track->setOutPort(mPort);

                MidiPort* mport = &midiPorts[track->outPort()];
                // this overwrites any instrument set for this port:
                mport->setInstrument(instr);

                EventList* mel = track->events();
                buildMidiEventList(mel, el, track, division, first, false, false);

                first = false;

                processTrack(track);

                song->insertTrack(track, -1);
                //Create the Audio input side of the track
                Track* input = song->addTrackByName(QString("i").append(track->name()), Track::AUDIO_INPUT, -1, false, false);
                if(input)
                {
                    input->setMasterFlag(false);
                    input->setChainMaster(track->id());
                    track->addManagedTrack(input->id());
                }
            }
        }
        if (first)
        {
            //
            // track does only contain non-channel messages
            // (SYSEX or META)
            //
            MidiTrack* track = new MidiTrack();
            track->setDefaultName();
            track->setMasterFlag(true);
            track->setOutChannel(0);
            track->setOutPort(mPort);
            EventList* mel = track->events();
            //buildMidiEventList(mel, el, track, division, true);
            // Do SysexMeta. Don't do loops.
            buildMidiEventList(mel, el, track, division, true, false, false);
            processTrack(track);
            song->insertTrack(track, -1);
            //Create the Audio input side of the track
            Track* input = song->addTrackByName(QString("i").append(track->name()), Track::AUDIO_INPUT, -1, false, false);
            if(input)
            {
                input->setMasterFlag(false);
                input->setChainMaster(track->id());
                track->addManagedTrack(input->id());
            }
        }
        mPort++;
        //FIXME: Provice a non-iterative way to do this using the new losMidiPorts hash
        //Or maintain a list of configured or inuse ports
        while((&midiPorts[mPort])->device() && mPort < MIDI_PORTS)
            mPort++;//Just incase we have a configured port after an empty one
    }

    if (!merge)
    {
        TrackList* tl = song->tracks();
        if (!tl->empty())
        {
            Track* track = tl->front();
            track->setSelected(true);
        }
        song->initLen();

        int z, n;
        AL::sigmap.timesig(0, z, n);

        int tempo = tempomap.tempo(0);
        transport->setTimesig(z, n);
        transport->setTempo(tempo);

        bool masterF = !tempomap.empty();
        song->setMasterFlag(masterF);
        transport->setMasterFlag(masterF);

        song->updatePos();

        composer->reset();
    }
    else
    {
        song->initLen();
    }

    return false;
}/*}}}*/
Пример #2
0
Файл: Song.cpp Проект: LMMS/lmms
void Song::processAutomations(const TrackList &tracklist, MidiTime timeStart, fpp_t)
{
	AutomatedValueMap values;

	QSet<const AutomatableModel*> recordedModels;

	TrackContainer* container = this;
	int tcoNum = -1;

	switch (m_playMode)
	{
	case Mode_PlaySong:
		break;
	case Mode_PlayBB:
	{
		Q_ASSERT(tracklist.size() == 1);
		Q_ASSERT(tracklist.at(0)->type() == Track::BBTrack);
		auto bbTrack = dynamic_cast<BBTrack*>(tracklist.at(0));
		auto bbContainer = Engine::getBBTrackContainer();
		container = bbContainer;
		tcoNum = bbTrack->index();
	}
		break;
	default:
		return;
	}

	values = container->automatedValuesAt(timeStart, tcoNum);
	TrackList tracks = container->tracks();

	Track::tcoVector tcos;
	for (Track* track : tracks)
	{
		if (track->type() == Track::AutomationTrack) {
			track->getTCOsInRange(tcos, 0, timeStart);
		}
	}

	// Process recording
	for (TrackContentObject* tco : tcos)
	{
		auto p = dynamic_cast<AutomationPattern *>(tco);
		MidiTime relTime = timeStart - p->startPosition();
		if (p->isRecording() && relTime >= 0 && relTime < p->length())
		{
			const AutomatableModel* recordedModel = p->firstObject();
			p->recordValue(relTime, recordedModel->value<float>());

			recordedModels << recordedModel;
		}
	}

	// Apply values
	for (auto it = values.begin(); it != values.end(); it++)
	{
		if (! recordedModels.contains(it.key()))
		{
			it.key()->setAutomatedValue(it.value());
		}
	}
}
Пример #3
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;
}
Пример #4
0
PyObject* getParts(PyObject*, PyObject* args)
{
	TrackList* tracks = song->tracks();
	const char* trackname;
	if (!PyArg_ParseTuple(args, "s", &trackname))
	{
		return NULL;
	}

	PyObject* pyparts = Py_BuildValue("[]");
	for (ciTrack t = tracks->begin(); t != tracks->end(); ++t)
	{
		Track* track = *t;
		if (track->name() != trackname)
			continue;

		PartList* parts = track->parts();
		for (ciPart p = parts->begin(); p != parts->end(); p++)
		{
			Part* part = p->second;

			MidiPart* mpart = (MidiPart*) part;
			PyObject* pypart = PyDict_New();
			int tick = mpart->tick();
			int lentick = mpart->lenTick();
			int serialnr = mpart->sn();
			PyObject* pstrtick = Py_BuildValue("s", "tick");
			PyObject* pitick = Py_BuildValue("i", tick);
			PyObject* pstrid = Py_BuildValue("s", "id");
			PyObject* pstrserial = Py_BuildValue("i", serialnr);
			PyObject* pstrlen = Py_BuildValue("s", "len");
			PyObject* pstrtick2 = Py_BuildValue("i", lentick);

			PyDict_SetItem(pypart, pstrtick, pitick);
			PyDict_SetItem(pypart, pstrid, pstrserial);
			PyDict_SetItem(pypart, pstrlen, pstrtick2);

			Py_DECREF(pstrtick);
			Py_DECREF(pitick);
			Py_DECREF(pstrid);
			Py_DECREF(pstrserial);
			Py_DECREF(pstrlen);
			Py_DECREF(pstrtick2);

			// Pack midi events into list before wrapping it all up
			EventList* events = mpart->events();
			PyObject* pyevents = Py_BuildValue("[]");
			for (ciEvent e = events->begin(); e != events->end(); e++)
			{
				PyObject* pyevent = PyDict_New(); // The event structure - a dictionary with keys 'type','tick','data'

				const Event& event = e->second;
				unsigned tick = e->first;
				PyObject* eventdata = Py_BuildValue("[i,i,i]", event.dataA(), event.dataB(), event.dataC());
				PyObject* pstrdata = Py_BuildValue("s", "data");
				pstrtick = Py_BuildValue("s", "tick");
				PyObject* pitickval = Py_BuildValue("i", tick);
				PyDict_SetItem(pyevent, pstrdata, eventdata);
				PyDict_SetItem(pyevent, pstrtick, pitickval);
				Py_DECREF(eventdata);
				Py_DECREF(pstrdata);
				Py_DECREF(pstrtick);
				Py_DECREF(pitickval);

				switch (event.type())
				{
					case Note:
					{
						PyObject* pstrtype = Py_BuildValue("s", "type");
						PyObject* pstrnote = Py_BuildValue("s", "note");
						PyObject* pstrlen = Py_BuildValue("s", "len");
						PyObject* pilentick = Py_BuildValue("i", event.lenTick());
						PyDict_SetItem(pyevent, pstrtype, pstrnote);
						PyDict_SetItem(pyevent, pstrlen, pilentick);
						Py_DECREF(pstrtype);
						Py_DECREF(pstrnote);
						Py_DECREF(pstrlen);
						Py_DECREF(pilentick);
						break;
					}
					case Controller:
					{
						PyObject* pstrtype = Py_BuildValue("s", "type");
						PyObject* pstrctrl = Py_BuildValue("s", "ctrl");
						PyDict_SetItem(pyevent, pstrtype, pstrctrl);
						Py_DECREF(pstrtype);
						Py_DECREF(pstrctrl);
						break;
					}
					default:
						printf("Event type not supported yet: %d\n", event.type());
						break;
				}
				PyList_Append(pyevents, pyevent);
				Py_DECREF(pyevent);
			}
			Py_DECREF(pyevents);
			// Add the event list to the pypart dictionary
			PyObject* pystrevents = Py_BuildValue("s", "events");
			PyDict_SetItem(pypart, pystrevents, pyevents);
			Py_DECREF(pystrevents);
			PyList_Append(pyparts, pypart);
			Py_DECREF(pypart);
		}

		return pyparts;
	}

	return NULL;
}
Пример #5
0
Файл: Song.cpp Проект: LMMS/lmms
void Song::processNextBuffer()
{
	m_vstSyncController.setPlaybackJumped( false );

	// if not playing, nothing to do
	if( m_playing == false )
	{
		return;
	}

	TrackList trackList;
	int tcoNum = -1; // track content object number

	// determine the list of tracks to play and the track content object
	// (TCO) number
	switch( m_playMode )
	{
		case Mode_PlaySong:
			trackList = tracks();
			// at song-start we have to reset the LFOs
			if( m_playPos[Mode_PlaySong] == 0 )
			{
				EnvelopeAndLfoParameters::instances()->reset();
			}
			break;

		case Mode_PlayBB:
			if( Engine::getBBTrackContainer()->numOfBBs() > 0 )
			{
				tcoNum = Engine::getBBTrackContainer()->
								currentBB();
				trackList.push_back( BBTrack::findBBTrack(
								tcoNum ) );
			}
			break;

		case Mode_PlayPattern:
			if( m_patternToPlay != NULL )
			{
				tcoNum = m_patternToPlay->getTrack()->
						getTCONum( m_patternToPlay );
				trackList.push_back(
						m_patternToPlay->getTrack() );
			}
			break;

		default:
			return;

	}

	// if we have no tracks to play, nothing to do
	if( trackList.empty() == true )
	{
		return;
	}

	// check for looping-mode and act if necessary
	TimeLineWidget * tl = m_playPos[m_playMode].m_timeLine;
	bool checkLoop =
		tl != NULL && m_exporting == false && tl->loopPointsEnabled();

	if( checkLoop )
	{
		// if looping-mode is enabled and we are outside of the looping
		// range, go to the beginning of the range
		if( m_playPos[m_playMode] < tl->loopBegin() ||
					m_playPos[m_playMode] >= tl->loopEnd() )
		{
			setToTime(tl->loopBegin());
			m_playPos[m_playMode].setTicks(
						tl->loopBegin().getTicks() );

			m_vstSyncController.setPlaybackJumped( true );

			emit updateSampleTracks();
		}
	}

	if( m_playPos[m_playMode].jumped() )
	{
		m_vstSyncController.setPlaybackJumped( true );
		m_playPos[m_playMode].setJumped( false );
	}

	f_cnt_t framesPlayed = 0;
	const float framesPerTick = Engine::framesPerTick();

	while( framesPlayed < Engine::mixer()->framesPerPeriod() )
	{
		m_vstSyncController.update();

		float currentFrame = m_playPos[m_playMode].currentFrame();
		// did we play a tick?
		if( currentFrame >= framesPerTick )
		{
			int ticks = m_playPos[m_playMode].getTicks() +
				( int )( currentFrame / framesPerTick );

			// did we play a whole tact?
			if( ticks >= MidiTime::ticksPerTact() )
			{
				// per default we just continue playing even if
				// there's no more stuff to play
				// (song-play-mode)
				int maxTact = m_playPos[m_playMode].getTact()
									+ 2;

				// then decide whether to go over to next tact
				// or to loop back to first tact
				if( m_playMode == Mode_PlayBB )
				{
					maxTact = Engine::getBBTrackContainer()
							->lengthOfCurrentBB();
				}
				else if( m_playMode == Mode_PlayPattern &&
					m_loopPattern == true &&
					tl != NULL &&
					tl->loopPointsEnabled() == false )
				{
					maxTact = m_patternToPlay->length()
								.getTact();
				}

				// end of played object reached?
				if( m_playPos[m_playMode].getTact() + 1
								>= maxTact )
				{
					// then start from beginning and keep
					// offset
					ticks %= ( maxTact * MidiTime::ticksPerTact() );

					// wrap milli second counter
					setToTimeByTicks(ticks);

					m_vstSyncController.setPlaybackJumped( true );
				}
			}
			m_playPos[m_playMode].setTicks( ticks );

			if (checkLoop || m_loopRenderRemaining > 1)
			{
				m_vstSyncController.startCycle(
					tl->loopBegin().getTicks(), tl->loopEnd().getTicks() );

				// if looping-mode is enabled and we have got
				// past the looping range, return to the
				// beginning of the range
				if( m_playPos[m_playMode] >= tl->loopEnd() )
				{
					if (m_loopRenderRemaining > 1) 
						m_loopRenderRemaining--;
					ticks = tl->loopBegin().getTicks();
					m_playPos[m_playMode].setTicks( ticks );
					setToTime(tl->loopBegin());

					m_vstSyncController.setPlaybackJumped( true );

					emit updateSampleTracks();
				}
			}
			else
			{
				m_vstSyncController.stopCycle();
			}

			currentFrame = fmodf( currentFrame, framesPerTick );
			m_playPos[m_playMode].setCurrentFrame( currentFrame );
		}

		if( framesPlayed == 0 )
		{
			// update VST sync position after we've corrected frame/
			// tick count but before actually playing any frames
			m_vstSyncController.setAbsolutePosition(
				m_playPos[m_playMode].getTicks()
				+ m_playPos[m_playMode].currentFrame()
				/ (double) framesPerTick );
		}

		f_cnt_t framesToPlay = 
			Engine::mixer()->framesPerPeriod() - framesPlayed;

		f_cnt_t framesLeft = ( f_cnt_t )framesPerTick -
						( f_cnt_t )currentFrame;
		// skip last frame fraction
		if( framesLeft == 0 )
		{
			++framesPlayed;
			m_playPos[m_playMode].setCurrentFrame( currentFrame
								+ 1.0f );
			continue;
		}
		// do we have samples left in this tick but these are less
		// than samples we have to play?
		if( framesLeft < framesToPlay )
		{
			// then set framesToPlay to remaining samples, the
			// rest will be played in next loop
			framesToPlay = framesLeft;
		}

		if( ( f_cnt_t ) currentFrame == 0 )
		{
			processAutomations(trackList, m_playPos[m_playMode], framesToPlay);

			// loop through all tracks and play them
			for( int i = 0; i < trackList.size(); ++i )
			{
				trackList[i]->play( m_playPos[m_playMode],
						framesToPlay,
						framesPlayed, tcoNum );
			}
		}

		// update frame-counters
		framesPlayed += framesToPlay;
		m_playPos[m_playMode].setCurrentFrame( framesToPlay +
								currentFrame );
		m_elapsedMilliSeconds[m_playMode] += MidiTime::ticksToMilliseconds(framesToPlay / framesPerTick, getTempo());
		m_elapsedTacts = m_playPos[Mode_PlaySong].getTact();
		m_elapsedTicks = ( m_playPos[Mode_PlaySong].getTicks() % ticksPerTact() ) / 48;
	}
}
Пример #6
0
void ControlToolBar::OnRecord(wxCommandEvent &evt)
{
   if (gAudioIO->IsBusy()) {
      #if (AUDACITY_BRANDING == BRAND_AUDIOTOUCH)
         if (mIsLocked) // Stop only if in locked mode. 
         {
            this->StopPlaying(); // Stop recording.
            mRecord->PopUp();
         }
         else
         {
            //v evt.GetClassInfo();
         }
      #else
         mRecord->PopUp();
      #endif
      return;
   }

   mPlay->Disable();
   #if (AUDACITY_BRANDING == BRAND_THINKLABS)
      mLoopPlay->Disable();
   #endif

   #if (AUDACITY_BRANDING == BRAND_AUDIOTOUCH)
      mStop->SetEnabled(mIsLocked);
   #else
      mStop->Enable();
   #endif
   mRewind->Disable();
   mFF->Disable();
   #if (AUDACITY_BRANDING == BRAND_AUDIOTOUCH)
      mPause->SetEnabled(mIsLocked);
      this->EnablePauseCommand(mIsLocked);
      this->SetRecord(mIsLocked); // If locked, push Record down, else up.
   #else
      mPause->Enable();
      mRecord->PushDown();
   #endif

   AudacityProject *p = GetActiveProject();
   if (p) {
      TrackList *t = p->GetTracks();

      // Don't do this for Audiotouch. Not necessary. The performance hit is in the track being recorded, below.
      #if (AUDACITY_BRANDING == BRAND_THINKLABS)
         // For versions that default to dual wave/spectrum display, 
         // switch all tracks to WaveformDisplay on Record, for performance.
         TrackListIterator iter(t);
         for (Track* pTrack = iter.First(); pTrack; pTrack = iter.Next())
            if (pTrack->GetKind() == Track::Wave)
               ((WaveTrack*)pTrack)->SetDisplay(WaveTrack::WaveformDisplay);
      #endif

      double t0 = p->GetSel0();
      double t1 = p->GetSel1();
      if (t1 == t0)
         t1 = 1000000000.0;     // record for a long, long time (tens of years)
      #if (AUDACITY_BRANDING == BRAND_AUDIOTOUCH)
         if (p->m_bWantAppendRecording)
         {
            t0 = t->GetEndTime();
            t1 = 1000000000.0;     // record for a long, long time (tens of years)
         }
         gAudioIO->SetWantLatencyCorrection(!p->m_bWantAppendRecording);
      #endif

      /* TODO: set up stereo tracks if that is how the user has set up
       * their preferences, and choose sample format based on prefs */
      WaveTrackArray newRecordingTracks, playbackTracks;

      bool duplex;
      gPrefs->Read("/AudioIO/Duplex", &duplex, true);
      int recordingChannels = gPrefs->Read("/AudioIO/RecordChannels", 1);

      if( duplex )
         playbackTracks = t->GetWaveTrackArray(false);
      else
         playbackTracks = WaveTrackArray();

      for( int c = 0; c < recordingChannels; c++ )
      {
         WaveTrack *newTrack = p->GetTrackFactory()->NewWaveTrack();
         newTrack->SetOffset(t0);
         newTrack->SetRate(p->GetRate());

         //v for performance     newTrack->SetDisplay(WaveTrack::WaveformAndSpectrumDisplay);
         newTrack->SetDisplay(WaveTrack::WaveformDisplay); 
         
         if( recordingChannels == 2 )
         {
            if( c == 0 )
            {
               newTrack->SetChannel(Track::LeftChannel);
               newTrack->SetLinked(true);
            }
            else
               newTrack->SetChannel(Track::RightChannel);
         }
         else
         {
            newTrack->SetChannel( Track::MonoChannel );
         }

         newRecordingTracks.Add(newTrack);
      }

      int token = gAudioIO->StartStream(playbackTracks,
                                        newRecordingTracks, t->GetTimeTrack(),
                                        p->GetRate(), t0, t1);

      bool success = (token != 0);
      for( unsigned int i = 0; i < newRecordingTracks.GetCount(); i++ )
         if (success)
            t->Add(newRecordingTracks[i]);
         else
            delete newRecordingTracks[i];

      if (success) {
         p->SetAudioIOToken(token);
         mBusyProject = p;
         SetVUMeters(p);
         #if (AUDACITY_BRANDING == BRAND_AUDIOTOUCH)
            this->SetBackgroundColour(*wxRED); // red for Recording
            this->Refresh();
         #endif
      }
      else {
         // msmeyer: Show error message if stream could not be opened
         wxMessageBox(_("Error while opening sound device. Please check the input "
                        "device settings and the project sample rate."),
                      _("Error"), wxOK | wxICON_EXCLAMATION, this);

         SetPlay(false);
         #if (AUDACITY_BRANDING == BRAND_AUDIOTOUCH)
            mStop->Enable(); // In case it was disabled above, based on mIsLocked.
         #endif
         SetStop(false);
         SetRecord(false);
      }

      #if (AUDACITY_BRANDING == BRAND_AUDIOTOUCH)
         p->OnZoomFitV();
      #endif
   }
}
Пример #7
0
void ControlToolBar::PlayPlayRegion(double t0, double t1,
                                    bool looped /* = false */)
{
   if (gAudioIO->IsBusy()) {
      mPlay->PopUp();
      #if (AUDACITY_BRANDING == BRAND_THINKLABS)
         mLoopPlay->PopUp();
      #elif (AUDACITY_BRANDING == BRAND_AUDIOTOUCH)
         mPlay->Show();
         mPause->Hide();
         this->EnablePauseCommand(false);
      #endif
      return;
   }
  
   mStop->Enable();
   mRewind->Disable();
   mRecord->Disable();
   mFF->Disable();
   mPause->Enable();
   this->EnablePauseCommand(true);
   
   AudacityProject *p = GetActiveProject();
   if (p) {
      TrackList *t = p->GetTracks();
      double maxofmins,minofmaxs;
      
      // JS: clarified how the final play region is computed;
      
      if (t1 == t0) {
         // msmeyer: When playing looped, we play the whole file, if
         // no range is selected. Otherwise, we play from t0 to end
         if (looped) {
            // msmeyer: always play from start
            t0 = t->GetStartTime();
         } else {
            // move t0 to valid range
            if (t0 < 0)
               t0 = t->GetStartTime();
            if (t0 > t->GetEndTime())
               t0 = t->GetEndTime();
         }
         
         // always play to end
         t1 = t->GetEndTime();
      }
      else {
         // always t0 < t1 right?

         // the set intersection between the play region and the
         // valid range maximum of lower bounds
         if (t0 < t->GetStartTime())
            maxofmins = t->GetStartTime();
         else
            maxofmins = t0;
         
         // minimum of upper bounds
         if (t1 > t->GetEndTime())
            minofmaxs = t->GetEndTime();
         else
            minofmaxs = t1;

         // we test if the intersection has no volume 
         if (minofmaxs <= maxofmins) {
            // no volume; play nothing
            return;
         }
         else {
            t0 = maxofmins;
            t1 = minofmaxs;
         }
      }

      bool success = false;
      if (t1 > t0) {
         int token =
            gAudioIO->StartStream(t->GetWaveTrackArray(false),
                                  WaveTrackArray(), t->GetTimeTrack(),
                                  p->GetRate(), t0, t1, looped);
         if (token != 0) {
            success = true;
            p->SetAudioIOToken(token);
            mBusyProject = p;
            SetVUMeters(p);
         }
         else {
            // msmeyer: Show error message if stream could not be opened
            wxMessageBox(_("Error while opening sound device. Please check the output "
                           "device settings and the project sample rate."),
                         _("Error"), wxOK | wxICON_EXCLAMATION, this);
         }
      }

      if (!success) {
         SetPlay(false);
         SetStop(false);
         SetRecord(false);
      }
      #if (AUDACITY_BRANDING == BRAND_AUDIOTOUCH)
         if (success)
         {
            mPlay->Hide();
            mPause->Show();
            this->EnablePauseCommand(true);

            this->SetBackgroundColour(*wxGREEN); // green for Playing
            this->Refresh();
         }
      #endif
   }
}
int main(int argc, char** argv) {
  init(argc, argv);

  if (argc != 3) {
    google::ShowUsageWithFlags(argv[0]);
    return 1;
  }

  std::string tracks_file = argv[1];
  std::string image_format = argv[2];
  std::string output_format = FLAGS_output_format;

  bool ok;

  TrackList<DrawerPointer> tracks;

  if (FLAGS_similarity) {
    // Load tracks.
    TrackList<SiftPosition> sift_tracks;
    SiftPositionReader feature_reader;
    ok = loadTrackList(tracks_file, sift_tracks, feature_reader);
    CHECK(ok) << "Could not load tracks";

    // Convert SIFT features to generic drawable features.
    siftPositionTracksToDrawers(sift_tracks, tracks);
  } else if (FLAGS_scale) {
    // Load tracks.
    TrackList<ScaleSpacePosition> scale_tracks;
    ScaleSpacePositionReader feature_reader;
    ok = loadTrackList(tracks_file, scale_tracks, feature_reader);
    CHECK(ok) << "Could not load tracks";

    // Convert SIFT features to generic drawable features.
    scaleFeatureTracksToDrawers(scale_tracks, tracks, FLAGS_radius);
  } else {
    // Load tracks.
    TrackList<cv::Point2d> point_tracks;
    ImagePointReader<double> feature_reader;
    ok = loadTrackList(tracks_file, point_tracks, feature_reader);
    CHECK(ok) << "Could not load tracks";

    // Convert SIFT features to generic drawable features.
    translationTracksToDrawers(point_tracks, tracks, FLAGS_radius);
  }

  LOG(INFO) << "Loaded " << tracks.size() << " tracks";

  // Make a list of random colors.
  typedef std::vector<cv::Scalar> ColorList;
  ColorList colors;
  for (int i = 0; i < int(tracks.size()); i += 1) {
    colors.push_back(randomColor(BRIGHTNESS, SATURATION));
  }

  // Iterate through frames in which track was observed.
  TrackListTimeIterator<DrawerPointer> frame(tracks, 0);

  while (!frame.end()) {
    // Get the current time.
    int t = frame.t();

    // Load the image.
    cv::Mat color_image;
    cv::Mat gray_image;
    ok = readImage(makeFilename(image_format, t), color_image, gray_image);
    CHECK(ok) << "Could not read image";

    // Get the features.
    typedef std::map<int, DrawerPointer> FeatureSet;
    FeatureSet features;
    frame.getPoints(features);

    // Draw each one with its color.
    drawFeatures(color_image, features, colors);

    if (FLAGS_save) {
      std::string output_file = makeFilename(output_format, t);
      ok = cv::imwrite(output_file, color_image);
      CHECK(ok) << "Could not save image";
    }

    if (FLAGS_display) {
      cv::imshow("tracks", color_image);
      cv::waitKey(10);
    }

    ++frame;
  }

  return 0;
}
Пример #9
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;
}
Пример #10
0
bool AudacityPrintout::OnPrintPage(int WXUNUSED(page))
{
   wxDC *dc = GetDC();
   if (!dc)
      return false;

   int width, height;
   dc->GetSize(&width, &height);

   int rulerScreenHeight = 40;
   int screenTotalHeight = mTracks->GetHeight() + rulerScreenHeight;

   double scale = height / (double)screenTotalHeight;

   int rulerPageHeight = (int)(rulerScreenHeight * scale);
   Ruler ruler;
   ruler.SetBounds(0, 0, width, rulerPageHeight);
   ruler.SetOrientation(wxHORIZONTAL);
   ruler.SetRange(0.0, mTracks->GetEndTime());
   ruler.SetFormat(Ruler::TimeFormat);
   ruler.SetLabelEdges(true);
   ruler.Draw(*dc);

   TrackArtist artist;
   artist.SetBackgroundBrushes(*wxWHITE_BRUSH, *wxWHITE_BRUSH,
                               *wxWHITE_PEN, *wxWHITE_PEN);
   ViewInfo viewInfo;
   viewInfo.selectedRegion = SelectedRegion();
   viewInfo.vpos = 0;
   viewInfo.h = 0.0;
   viewInfo.screen = mTracks->GetEndTime() - viewInfo.h;
   viewInfo.total = viewInfo.screen;
   viewInfo.zoom = viewInfo.lastZoom = width / viewInfo.screen;
   int y = rulerPageHeight;

   TrackListIterator iter(mTracks);
   Track *n = iter.First();
   while (n) {
      wxRect r;
      r.x = 0;
      r.y = y;
      r.width = width;
      r.height = (int)(n->GetHeight() * scale);

      artist.DrawTrack(n, *dc, r, &viewInfo, false, false, false, false);

      dc->SetPen(*wxBLACK_PEN);
      AColor::Line(*dc, 0, r.y, width, r.y);

#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
      if(MONO_WAVE_PAN(n)){
         y += r.height;
         r.x = 0;
         r.y = y;
         r.width = width;
         r.height = (int)(n->GetHeight(true) * scale);
         artist.DrawTrack(n, *dc, r, &viewInfo, false, false, false, false);
         dc->SetPen(*wxBLACK_PEN);
         AColor::Line(*dc, 0, r.y, width, r.y);
      }
#endif
      n = iter.Next();
      y += r.height;
   };

   return true;
}
Пример #11
0
void ControlToolBar::OnRecord(wxCommandEvent &evt)
{
   if (gAudioIO->IsBusy()) {
      mRecord->PopUp();
      return;
   }
   AudacityProject *p = GetActiveProject();
   if (p && p->GetCleanSpeechMode()) {
      size_t numProjects = gAudacityProjects.Count();
      bool tracks = (p && !p->GetTracks()->IsEmpty());
      if (tracks || (numProjects > 1)) {
         wxMessageBox(_("Recording in CleanSpeech mode is not possible when a track, or more than one project, is already open."),
            _("Recording not permitted"),
            wxOK | wxICON_INFORMATION,
            this);
         mRecord->PopUp();
         mRecord->Disable();
         return;
      }
   }

   if( evt.GetInt() == 1 ) // used when called by keyboard shortcut. Default (0) ignored.
      mRecord->SetShift(true);
   if( evt.GetInt() == 2 )
      mRecord->SetShift(false);

   SetRecord(true);

   if (p) {
      TrackList *t = p->GetTracks();
      TrackListIterator it(t);
      if(it.First() == NULL)
         mRecord->SetShift(false);
      double t0 = p->GetSel0();
      double t1 = p->GetSel1();
      if (t1 == t0)
         t1 = 1000000000.0;     // record for a long, long time (tens of years)

      /* TODO: set up stereo tracks if that is how the user has set up
       * their preferences, and choose sample format based on prefs */
      WaveTrackArray newRecordingTracks, playbackTracks;
/* REQUIRES PORTMIDI */
//      NoteTrackArray midiTracks;

      bool duplex;
      gPrefs->Read(wxT("/AudioIO/Duplex"), &duplex, true);
            
      if(duplex){
         playbackTracks = t->GetWaveTrackArray(false);
/* REQUIRES PORTMIDI */
//		 midiTracks = t->GetNoteTrackArray(false);
     }
      else {
         playbackTracks = WaveTrackArray();
/* REQUIRES PORTMIDI */
//		 midiTracks = NoteTrackArray();
     }
      
      // If SHIFT key was down, the user wants append to tracks
      int recordingChannels = 0;
      bool shifted = mRecord->WasShiftDown();
      if (shifted) {
         TrackListIterator it(t);
         WaveTrack *wt;
         bool sel = false;
         double allt0 = t0;

         // Find the maximum end time of selected and all wave tracks
         for (Track *tt = it.First(); tt; tt = it.Next()) {
            if (tt->GetKind() == Track::Wave) {
               wt = (WaveTrack *)tt;
               if (wt->GetEndTime() > allt0) {
                  allt0 = wt->GetEndTime();
               }
            
               if (tt->GetSelected()) {
                  sel = true;
                  if (duplex)
                     playbackTracks.Remove(wt);
                  if (wt->GetEndTime() > t0) {
                     t0 = wt->GetEndTime();
                  }
               }
            }
         }

         // Use end time of all wave tracks if none selected
         if (!sel) {
            t0 = allt0;
         }

         // Pad selected/all wave tracks to make them all the same length
         for (Track *tt = it.First(); tt; tt = it.Next()) {
            if (tt->GetKind() == Track::Wave && (tt->GetSelected() || !sel)) {
               wt = (WaveTrack *)tt;
               t1 = wt->GetEndTime();
               if (t1 < t0) {
                  WaveTrack *newTrack = p->GetTrackFactory()->NewWaveTrack();
                  newTrack->InsertSilence(0.0, t0 - t1);
                  newTrack->Flush();
                  wt->Clear(t1, t0);
                  wt->Paste(t1, newTrack);
                  delete newTrack;
               }
               newRecordingTracks.Add(wt);
            }
         }

         t1 = 1000000000.0;     // record for a long, long time (tens of years)
      }
      else {
         recordingChannels = gPrefs->Read(wxT("/AudioIO/RecordChannels"), 2);
         for (int c = 0; c < recordingChannels; c++) {
            WaveTrack *newTrack = p->GetTrackFactory()->NewWaveTrack();

            int initialheight = newTrack->GetHeight();

            newTrack->SetOffset(t0);

            if (recordingChannels <= 2) {
               newTrack->SetHeight(initialheight/recordingChannels);
            }
            else {
               newTrack->SetMinimized(true);
            }

            if (recordingChannels == 2) {
               if (c == 0) {
                  newTrack->SetChannel(Track::LeftChannel);
                  newTrack->SetLinked(true);
               }
               else {
                  newTrack->SetChannel(Track::RightChannel);
                  newTrack->SetTeamed(true);
               }
            }
            else {
               newTrack->SetChannel( Track::MonoChannel );
            }

            newRecordingTracks.Add(newTrack);
         }
         
         // msmeyer: StartStream calls a callback which triggers auto-save, so
         // we add the tracks where recording is done into now. We remove them
         // later if starting the stream fails
         for (unsigned int i = 0; i < newRecordingTracks.GetCount(); i++)
            t->Add(newRecordingTracks[i]);
      }

      int token = gAudioIO->StartStream(playbackTracks,
                                        newRecordingTracks,
/* REQUIRES PORTMIDI */
//                                        midiTracks,
                                        t->GetTimeTrack(),
                                        p->GetRate(), t0, t1, p);

      bool success = (token != 0);
      
      if (success) {
         p->SetAudioIOToken(token);
         mBusyProject = p;
         SetVUMeters(p);
      }
      else {
         // msmeyer: Delete recently added tracks if opening stream fails
         if (!shifted) {
            for (unsigned int i = 0; i < newRecordingTracks.GetCount(); i++) {
               t->Remove(newRecordingTracks[i]);
               delete newRecordingTracks[i];
            }
         }

         // msmeyer: Show error message if stream could not be opened
         wxMessageBox(_("Error while opening sound device. "
            wxT("Please check the input device settings and the project sample rate.")),
                      _("Error"), wxOK | wxICON_EXCLAMATION, this);

         SetPlay(false);
         SetStop(false);
         SetRecord(false);
      }
   }
}
Пример #12
0
void ControlToolBar::PlayPlayRegion(double t0, double t1,
                                    bool looped /* = false */,
                                    bool cutpreview /* = false */,
                                    TimeTrack *timetrack /* = NULL */)
{
   SetPlay(true);

   if (gAudioIO->IsBusy()) {
      SetPlay(false);
      return;
   }
   
   if (cutpreview && t0==t1) {
      SetPlay(false);
      return; /* msmeyer: makes no sense */
   }

   AudacityProject *p = GetActiveProject();
   if (!p) {
      SetPlay(false);
      return;  // Should never happen, but...
   }

   TrackList *t = p->GetTracks();
   if (!t) {
      mPlay->PopUp();
      return;  // Should never happen, but...
   }

   bool hasaudio = false;
   TrackListIterator iter(t);
   for (Track *trk = iter.First(); trk; trk = iter.Next()) {
      if (trk->GetKind() == Track::Wave) {
         hasaudio = true;
         break;
      }
   }

   if (!hasaudio) {
      SetPlay(false);
      return;  // No need to continue without audio tracks
   }

   double maxofmins,minofmaxs;
   
   // JS: clarified how the final play region is computed;
   if (t1 == t0) {
      // msmeyer: When playing looped, we play the whole file, if
      // no range is selected. Otherwise, we play from t0 to end
      if (looped) {
         // msmeyer: always play from start
         t0 = t->GetStartTime();
      } else {
         // move t0 to valid range
         if (t0 < 0)
            t0 = t->GetStartTime();
         if (t0 > t->GetEndTime())
            t0 = t->GetEndTime();
      }
      
      // always play to end
      t1 = t->GetEndTime();
   }
   else {
      // always t0 < t1 right?

      // the set intersection between the play region and the
      // valid range maximum of lower bounds
      if (t0 < t->GetStartTime())
         maxofmins = t->GetStartTime();
      else
         maxofmins = t0;
      
      // minimum of upper bounds
      if (t1 > t->GetEndTime())
         minofmaxs = t->GetEndTime();
      else
         minofmaxs = t1;

      // we test if the intersection has no volume 
      if (minofmaxs <= maxofmins) {
         // no volume; play nothing
         return;
      }
      else {
         t0 = maxofmins;
         t1 = minofmaxs;
      }
   }

   // Can't play before 0...either shifted or latencey corrected tracks
   if (t0 < 0.0) {
      t0 = 0.0;
   }
   
   bool success = false;
   if (t1 > t0) {
      int token;
      if (cutpreview) {
         double beforeLen, afterLen;
         gPrefs->Read(wxT("/AudioIO/CutPreviewBeforeLen"), &beforeLen, 1.0);
         gPrefs->Read(wxT("/AudioIO/CutPreviewAfterLen"), &afterLen, 1.0);
         double tcp0 = t0-beforeLen;
         double tcp1 = (t1+afterLen) - (t1-t0);
         SetupCutPreviewTracks(tcp0, t0, t1, tcp1);
         if (mCutPreviewTracks)
         {
            token = gAudioIO->StartStream(
               mCutPreviewTracks->GetWaveTrackArray(false),
               WaveTrackArray(), 
/* REQUIRES PORTMIDI */
//               NoteTrackArray(),
			   NULL, p->GetRate(), tcp0, tcp1, p, false,
               t0, t1-t0);
         } else
         {
            // Cannot create cut preview tracks, clean up and exit
            SetPlay(false);
            SetStop(false);
            SetRecord(false);
            return;
         }
      } else {
         if (!timetrack) {
            timetrack = t->GetTimeTrack();
         }
         token = gAudioIO->StartStream(t->GetWaveTrackArray(false),
                               WaveTrackArray(),
/* REQUIRES PORTMIDI */
//							   t->GetNoteTrackArray(false),
							   timetrack,
                               p->GetRate(), t0, t1, p, looped);
      }
      if (token != 0) {
         success = true;
         p->SetAudioIOToken(token);
         mBusyProject = p;
         SetVUMeters(p);
      }
      else {
         // msmeyer: Show error message if stream could not be opened
         wxMessageBox(_(
            "Error while opening sound device. "
            wxT("Please check the output device settings and the project sample rate.")),
            _("Error"), wxOK | wxICON_EXCLAMATION, this);
      }
   }

   if (!success) {
      SetPlay(false);
      SetStop(false);
      SetRecord(false);
   }
}