bool EffectSoundTouch::ProcessNoteTrack(Track *track)
{
   NoteTrack *nt = (NoteTrack *) track;
   if (nt == NULL) return false;
   nt->WarpAndTransposeNotes(mCurT0, mCurT1, *GetTimeWarper(), mSemitones);
   return true;
}
Example #2
0
bool NoteTrack::Paste(double t, Track *src)
{
   // Paste inserts src at time t. If src has a positive offset,
   // the offset is treated as silence which is also inserted. If
   // the offset is negative, the offset is ignored and the ENTIRE
   // src is inserted (otherwise, we would either lose data from
   // src by not inserting things at negative times, or inserting
   // things at negative times could overlap things already in
   // the destination track).

   //Check that src is a non-NULL NoteTrack
   if (src == NULL || src->GetKind() != Track::Note)
      return false;

   NoteTrack* other = (NoteTrack*)src;
   if (other->mSeq == NULL)
      return false;

   if(!mSeq)
      mSeq = new Alg_seq();

   if (other->GetOffset() > 0) {
      mSeq->convert_to_seconds();
      mSeq->insert_silence(t - GetOffset(), other->GetOffset());
      t += other->GetOffset();
   }
   mSeq->paste(t - GetOffset(), other->mSeq);

   return true;
}
Example #3
0
void AudacityProject::OnImportMIDI(wxCommandEvent & event)
{
   wxString path = gPrefs->Read("/DefaultOpenPath",::wxGetCwd());

   wxString fileName = wxFileSelector(_("Select a MIDI file..."),
                                      path,     // Path
                                      "",       // Name
                                      "",       // Extension
                                      _("All files (*.*)|*.*|"
                                        "MIDI files (*.mid)|*.mid|"
                                        "Allegro files (*.gro)|*.gro"),
                                      0,        // Flags
                                      this);    // Parent

   if (fileName != "") {
      path =::wxPathOnly(fileName);
      gPrefs->Write("/DefaultOpenPath", path);

      NoteTrack *newTrack = new NoteTrack(&mDirManager);

      if (::ImportMIDI(fileName, newTrack)) {

         SelectNone();
         mTracks->Add(newTrack);
         newTrack->SetSelected(true);

         PushState(wxString::Format(_("Imported MIDI from '%s'"),
                                    fileName.c_str()));

         FixScrollbars();
         mTrackPanel->Refresh(false);
      }
   }
}
Example #4
0
bool NoteTrack::Cut(double t0, double t1, Track **dest) {

    //dest goes onto clipboard
    *dest = NULL; // This is redundant
    if (t1 <= t0)
        return false;
    double len = t1-t0;

    NoteTrack *newTrack = new NoteTrack(mDirManager);

    newTrack->Init(*this);

    mSeq->convert_to_seconds();
    newTrack->mSeq = mSeq->cut(t0, len, false);

    mLen = (mLen <= len ? 0.0 : mLen - len);
    newTrack->mLen = len;

    // What should be done with the rest of newTrack's members?
    //(mBottomNote, mDirManager, mLastMidiPosition,
    // mSerializationBuffer, mSerializationLength, mVisibleChannels)

    *dest = newTrack;

    return true;
}
Example #5
0
void NoteTrack::WarpAndTransposeNotes(double t0, double t1,
                                      const TimeWarper &warper,
                                      double semitones)
{
   // Since this is a duplicate and duplicates convert mSeq to
   // a text string for saving as XML, we probably have to
   // duplicate again to get back an mSeq
   NoteTrack *nt = this;
   double offset = nt->GetOffset(); // track is shifted this amount
   if (!mSeq) { // replace saveme with an (unserialized) duplicate
      nt = (NoteTrack *) this->Duplicate();
      wxASSERT(!mSeq && nt->mSeq && !nt->mSerializationBuffer);
      // swap mSeq and Buffer between this and nt
      nt->mSerializationBuffer = mSerializationBuffer;
      nt->mSerializationLength = mSerializationLength;
      mSerializationBuffer = NULL;
      mSerializationLength = 0;
      mSeq = nt->mSeq;
      nt->mSeq = NULL;
      delete nt; // delete the duplicate
   }
   mSeq->convert_to_seconds(); // make sure time units are right
   t1 -= offset; // adjust time range to compensate for track offset
   t0 -= offset;
   if (t1 > mSeq->get_dur()) { // make sure t0, t1 are within sequence
      t1 = mSeq->get_dur();
      if (t0 >= t1) return;
   }
   Alg_iterator iter(mSeq, false);
   iter.begin();
   Alg_event_ptr event;
   while ((event = iter.next()) && event->time < t1) {
      if (event->is_note() && event->time >= t0 &&
          // Allegro data structure does not restrict channels to 16.
          // Since there is not way to select more than 16 channels,
          // map all channel numbers mod 16. This will have no effect
          // on MIDI files, but it will allow users to at least select
          // all channels on non-MIDI event sequence data.
          IsVisibleChan(event->chan % 16)) {
         event->set_pitch(event->get_pitch() + semitones);
      }
   }
   iter.end();
   // now, use warper to warp the tempo map
   mSeq->convert_to_beats(); // beats remain the same
   Alg_time_map_ptr map = mSeq->get_time_map();
   map->insert_beat(t0, map->time_to_beat(t0));
   map->insert_beat(t1, map->time_to_beat(t1));
   int i, len = map->length();
   for (i = 0; i < len; i++) {
      Alg_beat &beat = map->beats[i];
      beat.time = warper.Warp(beat.time + offset) - offset;
   }
   // about to redisplay, so might as well convert back to time now
   mSeq->convert_to_seconds();
}
Example #6
0
void NoteTrack::WriteXML(XMLWriter &xmlFile)
{
   std::ostringstream data;
   // Normally, Duplicate is called in pairs -- once to put NoteTrack
   // on the Undo stack, and again to move from the Undo stack to an
   // "active" editable state. For efficiency, we do not do a "real"
   // Duplicate followed by serialization into a binary blob. Instead,
   // we combine the Duplicate with serialization or unserialization.
   // Serialization and Unserialization happen on alternate calls to
   // Duplicate and (usually) produce the right results at the right
   // time.
   // It turns out that this optimized Duplicate is a little too
   // clever. There is at least one case where a track can be duplicated
   // and then AutoSave'd. (E.g. do an "Insert Silence" effect on a
   // NoteTrack.) In this case, mSeq will be NULL. To avoid a crash
   // and perform WriteXML, we may need to restore NoteTracks from binary
   // blobs to regular data structures (with an Alg_seq member).
   NoteTrack *saveme = this;
   if (!mSeq) { // replace saveme with an (unserialized) duplicate
      saveme = (NoteTrack *) this->Duplicate();
      assert(saveme->mSeq);
   }
   saveme->mSeq->write(data, true);
   xmlFile.StartTag(wxT("notetrack"));
   xmlFile.WriteAttr(wxT("name"), saveme->mName);
   xmlFile.WriteAttr(wxT("offset"), saveme->GetOffset());
   xmlFile.WriteAttr(wxT("visiblechannels"), saveme->mVisibleChannels);
   xmlFile.WriteAttr(wxT("height"), saveme->GetActualHeight());
   xmlFile.WriteAttr(wxT("minimized"), saveme->GetMinimized());
   xmlFile.WriteAttr(wxT("isSelected"), this->GetSelected());

#ifdef EXPERIMENTAL_MIDI_OUT
   xmlFile.WriteAttr(wxT("velocity"), (double) saveme->mGain);
#endif
   xmlFile.WriteAttr(wxT("bottomnote"), saveme->mBottomNote);
   xmlFile.WriteAttr(wxT("data"), wxString(data.str().c_str(), wxConvUTF8));
   xmlFile.EndTag(wxT("notetrack"));
   if (this != saveme) {
      delete saveme; // delete the duplicate
   }
}
Example #7
0
bool NoteTrack::Copy(double t0, double t1, Track **dest){

   //dest goes onto clipboard
   *dest = NULL; // This is redundant and matches WaveTrack::Copy
   if (t1 <= t0)
      return false;
   double len = t1-t0;

   NoteTrack *newTrack = new NoteTrack(mDirManager);

   newTrack->Init(*this);

   mSeq->convert_to_seconds();
   newTrack->mSeq = mSeq->copy(t0 - GetOffset(), len, false);
   newTrack->SetOffset(GetOffset());

   // What should be done with the rest of newTrack's members?
   //(mBottomNote, mDirManager, mLastMidiPosition,
   // mSerializationBuffer, mSerializationLength, mVisibleChannels)

   *dest = newTrack;

   return true;
}
Example #8
0
Track *NoteTrack::Duplicate()
{
   NoteTrack *duplicate = new NoteTrack(mDirManager);
   duplicate->Init(*this);
   // Duplicate on NoteTrack moves data from mSeq to mSerializationBuffer
   // and from mSerializationBuffer to mSeq on alternate calls. Duplicate
   // to the undo stack and Duplicate back to the project should result
   // in serialized blobs on the undo stack and traversable data in the
   // project object.
   if (mSeq) {
      SonifyBeginSerialize();
      assert(!mSerializationBuffer);
      // serialize from this to duplicate's mSerializationBuffer
      mSeq->serialize((void**)&duplicate->mSerializationBuffer,
                      &duplicate->mSerializationLength);
      SonifyEndSerialize();
   } else if (mSerializationBuffer) {
      SonifyBeginUnserialize();
      assert(!mSeq);
      Alg_track_ptr alg_track = Alg_seq::unserialize(mSerializationBuffer,
                                                      mSerializationLength);
      assert(alg_track->get_type() == 's');
      duplicate->mSeq = (Alg_seq_ptr) alg_track;
      SonifyEndUnserialize();
   } else assert(false); // bug if neither mSeq nor mSerializationBuffer
   // copy some other fields here
   duplicate->SetBottomNote(mBottomNote);
   duplicate->SetPitchHeight(mPitchHeight);
   duplicate->mLastMidiPosition = mLastMidiPosition;
   duplicate->mVisibleChannels = mVisibleChannels;
   duplicate->SetOffset(GetOffset());
#ifdef EXPERIMENTAL_MIDI_OUT
   duplicate->SetGain(GetGain());
#endif
   return duplicate;
}
Example #9
0
bool MeshExpUtility::SaveSkinKeys(const char* n){
	CFS_Memory F;

	int FramesPerSecond = GetFrameRate();
	int TicksPerFrame	= GetTicksPerFrame();
	int FirstTick		= ip->GetAnimRange().Start();
	int LastTick		= ip->GetAnimRange().End();

	Point3 v;
	Matrix3 tm;

	// Write signature and version
	char S[MAX_PATH];
	sprintf(S, "KEYEXP 3.0");
	F.Wstring(S);

	INode *node;
	ObjectEntry *Current;

	//-----------------------------------------------------------------------
	// Count bones and report

	int NumBones = 0;
	Current = theObjects->head;
	while(Current)
	{
		/*
		if(Current->entry->type != OBTYPE_BONE)
		{
			Current = Current->next;
			continue;
		}
		*/

		NumBones++;

		Current = Current->next;
	}

	sprintf(S, "Number of Bones = %d", NumBones);
	F.Wstring(S);
	ELog.Msg(mtInformation,S);

	//-----------------------------------------------------------------------
	// Write out necessary data for motion keys

	sprintf(S, "Key Data");
	F.Wstring(S);

	TimeValue t;
	Quat qq;
	Point3 tp, sp;
	INode* parent;
	Matrix3 tmp;

	sprintf(S, "%d %d %d", FirstTick / TicksPerFrame, LastTick / TicksPerFrame, FramesPerSecond);
	F.Wstring(S);

	Current = theObjects->head;
	while(Current){
		/*
		if(Current->entry->type != OBTYPE_BONE)
		{
			Current = Current->next;
			continue;
		}
		*/

		Matrix3 tm;

		node = Current->entry->node;

		sprintf(S, "Node: %s", node->GetName());
		F.Wstring(S);
		ELog.Msg(mtInformation,S);

		// Print notetrack info
		{
			int NumNT, n, i, j, NumNotes;
			NoteTrack* pNT;
			DefNoteTrack* pDNT;
			NoteKey* pNK;

			NumNT = node->NumNoteTracks();

			// count all of the notes on all of the notetracks
			NumNotes = 0;
			for(n=0;n<NumNT;n++){
				pNT = node->GetNoteTrack(n);
				if(pNT->ClassID() == Class_ID(NOTETRACK_CLASS_ID, 0)){
					pDNT = (DefNoteTrack*)pNT;
					j = pDNT->NumKeys();
					for(i=0;i<j;i++){
						pNK = pDNT->keys[i];
						if( (pNK->time >= FirstTick) && (pNK->time <= LastTick) )
							NumNotes++;
					}
				}
			}

			sprintf(S, "Number of Notes = %d", NumNotes);
			F.Wstring(S);

			for(n=0;n<NumNT;n++){
				pNT = node->GetNoteTrack(n);
				if(pNT->ClassID() == Class_ID(NOTETRACK_CLASS_ID, 0)){
					pDNT = (DefNoteTrack*)pNT;
					j = pDNT->NumKeys();
					for(i=0;i<j;i++){
						pNK = pDNT->keys[i];
						if( (pNK->time >= FirstTick) && (pNK->time <= LastTick) ){
							sprintf(S, "%d: %s", (pNK->time - FirstTick) / TicksPerFrame, pNK->note);
							F.Wstring(S);
						}
					}
				}
			}
		}

		for(t=FirstTick;t<=LastTick;t+=TicksPerFrame){
			tm = node->GetNodeTM(t);
			DecomposeMatrix(tm, tp, qq, sp);
			qq.MakeMatrix	(tm);
			tm.SetTrans		(tp);

			parent = node->GetParentNode();
			if(parent){
				tmp = parent->GetNodeTM(t);
				DecomposeMatrix(tmp, tp, qq, sp);
				qq.MakeMatrix(tmp);
				tmp.SetTrans(tp);
				tmp = Inverse(tmp);
				tm *= tmp;
			}

			DecomposeMatrix(tm, tp, qq, sp);
			sprintf(S,"%f %f %f %f",qq.x, qq.y, qq.z, qq.w);
			F.Wstring(S);
			sprintf(S,"%f %f %f",tp.x,tp.y,tp.z);
			F.Wstring(S);

			/*
			// Euler angles
			Point3			E;
			QuatToEuler		(Quat(tm), E);
			fprintf			(f,"%f %f %f",E.x,E.y,E.z);

			// Translate
			DecomposeMatrix	(tm, tp, qq, sp);
			fprintf			(f,"%f %f %f",tp.x,tp.y,tp.z);
			*/

//			Matrix3fprint(f, tm);
		}
		Current = Current->next;
	}

	sprintf(S, "Key Data Complete");
	F.Wstring(S);
	ELog.Msg(mtInformation,S);

	F.SaveTo(n,0);

	return true;
}
Example #10
0
void StretchHandle::Stretch(AudacityProject *pProject, int mouseXCoordinate, int trackLeftEdge,
   Track *pTrack)
{
   ViewInfo &viewInfo = pProject->GetViewInfo();

   if (pTrack == NULL && mpTrack != NULL)
      pTrack = mpTrack.get();

   if (!pTrack || pTrack->GetKind() != Track::Note) {
      return;
   }

   NoteTrack *pNt = static_cast<NoteTrack *>(pTrack);
   double moveto =
      std::max(0.0, viewInfo.PositionToTime(mouseXCoordinate, trackLeftEdge));

   double dur, left_dur, right_dur;

   // check to make sure tempo is not higher than 20 beats per second
   // (In principle, tempo can be higher, but not infinity.)
   double minPeriod = 0.05; // minimum beat period

   // make sure target duration is not too short
   // Take quick exit if so, without changing the selection.
   auto t0 = mStretchState.mBeat0.first;
   auto t1 = mStretchState.mBeat1.first;
   switch ( mStretchState.mMode ) {
   case stretchLeft: {
      dur = t1 - moveto;
      if (dur < mStretchState.mRightBeats * minPeriod)
         return;
      pNt->StretchRegion
         ( mStretchState.mBeat0, mStretchState.mBeat1, dur );
      pNt->Offset( moveto - t0 );
      mStretchState.mBeat0.first = moveto;
      viewInfo.selectedRegion.setT0(moveto);
      break;
   }
   case stretchRight: {
      dur = moveto - t0;
      if (dur < mStretchState.mLeftBeats * minPeriod)
         return;
      pNt->StretchRegion
         ( mStretchState.mBeat0, mStretchState.mBeat1, dur );
      viewInfo.selectedRegion.setT1(moveto);
      mStretchState.mBeat1.first = moveto;
      break;
   }
   case stretchCenter: {
      moveto = std::max(t0, std::min(t1, moveto));
      left_dur = moveto - t0;
      right_dur = t1 - moveto;
      if ( left_dur < mStretchState.mLeftBeats * minPeriod ||
           right_dur < mStretchState.mRightBeats * minPeriod )
         return;
      pNt->StretchRegion
         ( mStretchState.mBeatCenter, mStretchState.mBeat1, right_dur );
      pNt->StretchRegion
         ( mStretchState.mBeat0, mStretchState.mBeatCenter, left_dur );
      mStretchState.mBeatCenter.first = moveto;
      break;
   }
   default:
      wxASSERT(false);
      break;
   }
}