/********************************************************************** Audacity: A Digital Audio Editor NoteTrack.cpp Dominic Mazzoni *******************************************************************//*! \class NoteTrack \brief A Track that is used for Midi notes. (Somewhat old code). *//*******************************************************************/ #include #include #include #include #include "Audacity.h" #if defined(USE_MIDI) #include "allegro.h" /* REQUIRES PORTMIDI */ //#include "portmidi.h" //#include "porttime.h" #include "AColor.h" #include "NoteTrack.h" #include "DirManager.h" NoteTrack *TrackFactory::NewNoteTrack() { return new NoteTrack(mDirManager); } NoteTrack::NoteTrack(DirManager * projDirManager): Track(projDirManager) { SetDefaultName(_("Note Track")); SetName(GetDefaultName()); mSeq = NULL; mLen = 0.0; mSerializationBuffer = NULL; mSerializationLength = 0; mDirManager = projDirManager; mBottomNote = 24; mVisibleChannels = 0xFFFF; mLastMidiPosition = 0; } NoteTrack::~NoteTrack() { if (mSerializationBuffer) { delete [] mSerializationBuffer; } if (mSeq) { delete mSeq; } } Track *NoteTrack::Duplicate() { NoteTrack *duplicate = new NoteTrack(mDirManager); // 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) { assert(!mSerializationBuffer); // serialize from this to duplicate's mSerializationBuffer mSeq->serialize((void**)&duplicate->mSerializationBuffer, &duplicate->mSerializationLength); } else if (mSerializationBuffer) { 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; } else assert(false); // bug if neither mSeq nor mSerializationBuffer // copy some other fields here duplicate->mBottomNote = mBottomNote; duplicate->mLastMidiPosition = mLastMidiPosition; duplicate->mLen = mLen; duplicate->mVisibleChannels = mVisibleChannels; return duplicate; } void NoteTrack::DrawLabelControls(wxDC & dc, wxRect & r) { int wid = 23; int ht = 16; if (r.height < ht * 4) { return; } int x = r.x + (r.width / 2 - wid * 2) + 2; int y = r.y + 5; for (int row = 0; row < 4; row++) { for (int col = 0; col < 4; col++) { int channel = row * 4 + col + 1; wxRect box; box.x = x + col * wid; box.y = y + row * ht; box.width = wid; box.height = ht; if (mVisibleChannels & (1 << (channel - 1))) { AColor::MIDIChannel(&dc, channel); dc.DrawRectangle(box); AColor::LightMIDIChannel(&dc, channel); AColor::Line(dc, box.x, box.y, box.x + box.width - 1, box.y); AColor::Line(dc, box.x, box.y, box.x, box.y + box.height - 1); AColor::DarkMIDIChannel(&dc, channel); AColor::Line(dc, box.x + box.width - 1, box.y, box.x + box.width - 1, box.y + box.height - 1); AColor::Line(dc, box.x, box.y + box.height - 1, box.x + box.width - 1, box.y + box.height - 1); } else { AColor::MIDIChannel(&dc, 0); dc.DrawRectangle(box); } wxString t; long w; long h; t.Printf(wxT("%d"), channel); dc.GetTextExtent(t, &w, &h); dc.DrawText(t, box.x + (box.width - w) / 2, box.y + (box.height - h) / 2); } } } bool NoteTrack::LabelClick(wxRect & r, int mx, int my, bool right) { int wid = 23; int ht = 16; if (r.height < ht * 4) return false; int x = r.x + (r.width / 2 - wid * 2); int y = r.y + 1; int col = (mx - x) / wid; int row = (my - y) / ht; if (row < 0 || row >= 4 || col < 0 || col >= 4) return false; int channel = row * 4 + col; if (right) { if (mVisibleChannels == (1 << channel)) mVisibleChannels = 0xFFFF; else mVisibleChannels = (1 << channel); } else mVisibleChannels ^= (1 << channel); return true; } void NoteTrack::SetSequence(Alg_seq_ptr seq) { if (mSeq) delete mSeq; mSeq = seq; mLen = (seq ? seq->get_real_dur() : 0.0); } Alg_seq* NoteTrack::GetSequence() { return mSeq; } void NoteTrack::PrintSequence() { FILE *debugOutput; debugOutput = fopen("debugOutput.txt", "wt"); fprintf(debugOutput, "Importing MIDI...\n"); if (mSeq) { int i = 0; while(i < mSeq->length()) { fprintf(debugOutput, "--\n"); fprintf(debugOutput, "type: %c\n", ((Alg_event_ptr)mSeq->track_list.tracks[i])->get_type()); fprintf(debugOutput, "time: %f\n", ((Alg_event_ptr)mSeq->track_list.tracks[i])->time); fprintf(debugOutput, "channel: %li\n", ((Alg_event_ptr)mSeq->track_list.tracks[i])->chan); if(((Alg_event_ptr)mSeq->track_list.tracks[i])->get_type() == wxT('n')) { fprintf(debugOutput, "pitch: %f\n", ((Alg_note_ptr)mSeq->track_list.tracks[i])->pitch); fprintf(debugOutput, "duration: %f\n", ((Alg_note_ptr)mSeq->track_list.tracks[i])->dur); fprintf(debugOutput, "velocity: %f\n", ((Alg_note_ptr)mSeq->track_list.tracks[i])->loud); } else if(((Alg_event_ptr)mSeq->track_list.tracks[i])->get_type() == wxT('n')) { fprintf(debugOutput, "key: %li\n", ((Alg_update_ptr)mSeq->track_list.tracks[i])->get_identifier()); fprintf(debugOutput, "attribute type: %c\n", ((Alg_update_ptr)mSeq->track_list.tracks[i])->parameter.attr_type()); fprintf(debugOutput, "attribute: %s\n", ((Alg_update_ptr)mSeq->track_list.tracks[i])->parameter.attr_name()); if(((Alg_update_ptr)mSeq->track_list.tracks[i])->parameter.attr_type() == wxT('r')) { fprintf(debugOutput, "value: %f\n", ((Alg_update_ptr)mSeq->track_list.tracks[i])->parameter.r); } else if(((Alg_update_ptr)mSeq->track_list.tracks[i])->parameter.attr_type() == wxT('i')) { fprintf(debugOutput, "value: %li\n", ((Alg_update_ptr)mSeq->track_list.tracks[i])->parameter.i); } else if(((Alg_update_ptr)mSeq->track_list.tracks[i])->parameter.attr_type() == wxT('s')) { fprintf(debugOutput, "value: %s\n", ((Alg_update_ptr)mSeq->track_list.tracks[i])->parameter.s); } else {} } i++; } } else { fprintf(debugOutput, "No sequence defined!\n"); } fclose(debugOutput); } int NoteTrack::GetVisibleChannels() { return mVisibleChannels; } 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; } 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, len, false); newTrack->mLen = len; // What should be done with the rest of newTrack's members? //(mBottomNote, mDirManager, mLastMidiPosition, // mSerializationBuffer, mSerializationLength, mVisibleChannels) *dest = newTrack; return true; } bool NoteTrack::Clear(double t0, double t1){ // If t1 = t0, should Clear return true? if (t1 <= t0) return false; double len = t1-t0; mSeq->clear(t0, len, false); return true; } bool NoteTrack::Paste(double t, Track *src){ //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(); mSeq->paste(t, other->mSeq); mLen = mSeq->get_real_dur(); return true; } bool NoteTrack::ExportMIDI(wxString f) { return mSeq->smf_write(f.mb_str()); } bool NoteTrack::ExportAllegro(wxString f) { return mSeq->write(f.mb_str()); } bool NoteTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs) { return false; } XMLTagHandler *NoteTrack::HandleXMLChild(const wxChar *tag) { return NULL; } void NoteTrack::WriteXML(XMLWriter &xmlFile) { } #endif // USE_MIDI // Indentation settings for Vim and Emacs and unique identifier for Arch, a // version control system. Please do not modify past this point. // // Local Variables: // c-basic-offset: 3 // indent-tabs-mode: nil // End: // // vim: et sts=3 sw=3 // arch-tag: ecfdee12-5b16-4f27-84d1-4a3800d07d1e