diff --git a/SpiralSound/Plugins/SequencerPlugin/Makefile.in b/SpiralSound/Plugins/SequencerPlugin/Makefile.in index 68d62ef..f431318 100644 --- a/SpiralSound/Plugins/SequencerPlugin/Makefile.in +++ b/SpiralSound/Plugins/SequencerPlugin/Makefile.in @@ -184,7 +184,7 @@ SequencerPlugin.o: SequencerPlugin.C \ SequencerPluginGUI.o: SequencerPluginGUI.C \ SequencerPluginGUI.h \ - SequencerPluginss.h \ + SequencerPlugin.h \ ../SpiralPlugin.h \ ../../Sample.h \ ../../SpiralInfo.h \ diff --git a/SpiralSound/Plugins/SequencerPlugin/SequencerPlugin.C b/SpiralSound/Plugins/SequencerPlugin/SequencerPlugin.C index 92fedcd..3ae4dc4 100644 --- a/SpiralSound/Plugins/SequencerPlugin/SequencerPlugin.C +++ b/SpiralSound/Plugins/SequencerPlugin/SequencerPlugin.C @@ -25,6 +25,398 @@ // for note on's static const float TRIGGER_LEV=0.1; +////////////////////////////////////////////////////////////////////////// +// base sequencing stuff + +Note::Note(float t=0, float l=0.1f, int n=0, float v=1.0f) +{ + Time = t; + Length = l; + MidiNote = n; + Vol = v; +} + +Note::~Note() +{ +} + +istream &operator>>(istream &s, Note &o) +{ + int version=1; + string dummy; + s>>version>>dummy>>o.Time>>o.Length>>o.MidiNote>>o.Vol; + + return s; +} + +ostream &operator<<(ostream &s, Note &o) +{ + int version=1; + s<m_NoteMap; + + int c=0; + for (map::const_iterator i = o->m_NoteMap.begin(); + i!=o->m_NoteMap.end(); i++) + { + m_NoteMap[c++]=i->second; + } +} + +void Pattern::AddNote(int ID, float t, float l, int n, float v) +{ + map::iterator i = m_NoteMap.find(ID); + if (i != m_NoteMap.end()) + { + cerr<<"duplicate note "<::iterator i = m_NoteMap.find(ID); + if (i == m_NoteMap.end()) + { + cerr<<"couldn't find note "<::iterator i = m_NoteMap.find(ID); + if (i == m_NoteMap.end()) + { + cerr<<"couldn't find note "<second; +} + +istream &operator>>(istream &s, Pattern &o) +{ + int version=1,Num; + string dummy; + int id=0; + s>>version>>dummy>>Num; + for (int n=0; n>t; + o.m_NoteMap[id++]=t; + } + + return s; +} + +ostream &operator<<(ostream &s, Pattern &o) +{ + int version=1; + s<::iterator i = o.m_NoteMap.begin(); + i!=o.m_NoteMap.end(); i++) + { + s<second; + } + s<>(istream &s, Sequence &o) +{ + int version=1; + string dummy; + s>>version>>dummy>>o.m_StartTime>>o.m_Pattern>>o.m_Colour>>o.m_YPos>>o.m_Length>>o.m_Channel; + + char Buf[4096]; + int size; + s>>size; + s.ignore(1); + s.get(Buf,size+1); + o.m_Name=Buf; + + return s; +} + +ostream &operator<<(ostream &s, Sequence &o) +{ + int version=1; + s<::iterator i = m_SequenceMap.find(ID); + if (i != m_SequenceMap.end()) + { + cerr<<"duplicate sequence "<SetColour(GetSequence(ID)->GetColour()); + s->SetName(GetSequence(ID)->GetName()); + s->SetLength(GetSequence(ID)->GetLength()); + s->SetYPos(GetSequence(ID)->GetYPos()); + s->SetPatternID(GetSequence(ID)->GetPatternID()); + s->SetStartTime(GetSequence(ID)->GetStartTime()); + s->SetChannel(GetSequence(ID)->GetChannel()); +} + +// duplicate the sequence, and copy the pattern to it's own version +void Track::CopySequence(int ID, int nID) +{ + AddSequence(nID); + Sequence *s=GetSequence(nID); + s->SetColour(GetSequence(ID)->GetColour()); + s->SetName(GetSequence(ID)->GetName()); + s->SetLength(GetSequence(ID)->GetLength()); + s->SetYPos(GetSequence(ID)->GetYPos()); + s->SetStartTime(GetSequence(ID)->GetStartTime()); + s->SetChannel(GetSequence(ID)->GetChannel()); + AddPattern(m_NextPatternID); + GetPattern(m_NextPatternID)->Copy(GetPattern(GetSequence(ID)->GetPatternID())); + GetSequence(nID)->SetPatternID(m_NextPatternID); + m_NextPatternID++; +} + +// copy the sequences pattern, so it's got it's own version +void Track::InstanceSequence(int ID) +{ + AddPattern(m_NextPatternID); + GetPattern(m_NextPatternID)->Copy(GetPattern(GetSequence(ID)->GetPatternID())); + GetSequence(ID)->SetPatternID(m_NextPatternID); + m_NextPatternID++; +} + +void Track::RemoveSequence(int ID) +{ + map::iterator i = m_SequenceMap.find(ID); + if (i == m_SequenceMap.end()) + { + cerr<<"couldn't find sequence "<::iterator i = m_SequenceMap.find(ID); + if (i == m_SequenceMap.end()) + { + cerr<<"couldn't find sequence "<second; +} + +void Track::AddNote(int ID, int Sequence, float t, float l, int n, float v) +{ + GetPattern(GetSequence(Sequence)->GetPatternID())->AddNote(ID,t,l,n,v); +} + +void Track::RemoveNote(int ID, int Sequence) +{ + GetPattern(GetSequence(Sequence)->GetPatternID())->RemoveNote(ID); +} + +void Track::ChangeNote(int ID, int Sequence, float t, float l, int n, float v) +{ + Note *note = GetPattern(GetSequence(Sequence)->GetPatternID())->GetNote(ID); + note->Time = t; + note->Length = l; + note->MidiNote = n; + note->Vol = v; +} + +void Track::ReadTrack(float t, int channel, vector &NoteVec) +{ + // for every sequence + for (map::iterator i = m_SequenceMap.begin(); + i!=m_SequenceMap.end(); i++) + { + if (i->second.GetChannel()==channel) + { + Pattern *p=GetPattern(i->second.GetPatternID()); + float SeqTime=i->second.GetStartTime(); + + // for every note in the pattern + for (map::iterator n = p->m_NoteMap.begin(); + n!=p->m_NoteMap.end(); n++) + { + if (n->second.Time+SeqTimesecond.Time+n->second.Length+SeqTime>t) + { + NoteVec.push_back(n->second); + } + } + } + } +} + +//// private ////// + +void Track::AddPattern(int ID) +{ + map::iterator i = m_PatternMap.find(ID); + if (i != m_PatternMap.end()) + { + cerr<<"duplicate pattern "<::iterator i = m_PatternMap.find(ID); + if (i == m_PatternMap.end()) + { + cerr<<"couldn't find pattern "<::iterator i = m_PatternMap.find(ID); + if (i == m_PatternMap.end()) + { + cerr<<"couldn't find pattern "<second; +} + +istream &operator>>(istream &s, Track &o) +{ + int version=1,Num,id=0; + string dummy; + s>>version>>dummy; + + s>>Num; + for (int n=0; n>t; + o.m_PatternMap[id++]=t; + } + s>>Num; + id=0; + for (int n=0; n>t; + o.m_SequenceMap[id++]=t; + + cerr<<"Loaded sequence "<>o.m_NextPatternID; + o.m_NextPatternID=o.m_PatternMap.size(); + return s; +} + +ostream &operator<<(ostream &s, Track &o) +{ + int version=1; + + s<::iterator i = o.m_PatternMap.begin(); + i!=o.m_PatternMap.end(); i++) + { + s<second; + } + + s<::iterator i = o.m_SequenceMap.begin(); + i!=o.m_SequenceMap.end(); i++) + { + s<second; + } + s<Register("ID",&m_GUIArgs.Num); + m_AudioCH->Register("ID2",&m_GUIArgs.Num2); + m_AudioCH->Register("Channel",&m_GUIArgs.Channel); + m_AudioCH->Register("Sequence",&m_GUIArgs.Sequence); + m_AudioCH->Register("Time",&m_GUIArgs.t); + m_AudioCH->Register("Length",&m_GUIArgs.l); + m_AudioCH->Register("Vol",&m_GUIArgs.v); + m_AudioCH->Register("Note",&m_GUIArgs.n); + m_AudioCH->Register("CurrentTime",&m_Time,ChannelHandler::OUTPUT); + m_AudioCH->Register("TotalLength",&m_Length); + m_AudioCH->Register("BeatsPerBar",&m_BeatsPerBar); + m_AudioCH->Register("BarLength",&m_BarLength); + m_AudioCH->RegisterData("Name",ChannelHandler::INPUT,m_GUIArgs.Name,sizeof(m_GUIArgs.Name)); + + // use OUTPUT_REQUEST for these, as we don't have to copy them constantly (and the gui can request them) + m_AudioCH->Register("TransCount",&m_TransferCount,ChannelHandler::OUTPUT_REQUEST); + m_AudioCH->RegisterData("TransNote",ChannelHandler::OUTPUT_REQUEST,&m_Transfer,sizeof(m_Transfer)); } SequencerPlugin::~SequencerPlugin() @@ -171,35 +617,55 @@ void SequencerPlugin::Execute() } } - - - // Get the notes from the map - /*vector NoteVec=m_Eventmap[m_CurrentPattern]->GetEvents(m_Time); - - // play all the notes found - for (vector::iterator i=NoteVec.begin(); - i!=NoteVec.end(); i++) + for (int channel=0; channelm_Type==EventInfo::START) - { - m_CurrentNoteCV=NoteTable[i->m_Group]; - m_CurrentTriggerCV=1; - } - - if (i->m_Type==EventInfo::END) - { - m_CurrentTriggerCV=0; - if (m_NoteCut) m_CurrentNoteCV=0; + // Get the notes from the map + vector NoteVec; + m_Track.ReadTrack(m_Time,channel,NoteVec); + + m_CurrentTriggerCV[channel]=0; + //m_CurrentNoteCV=0; + + // play all the notes found + for (vector::iterator i=NoteVec.begin(); + i!=NoteVec.end(); i++) + { + //cerr<<"time = "<Time<<" "<Length<MidiNote]; + m_CurrentTriggerCV[channel]=1; } + SetOutputPitch(channel*2,n,m_CurrentNoteCV[channel]); + SetOutput(channel*2+1,n,m_CurrentTriggerCV[channel]); } -*/ - SetOutputPitch(0,n,m_CurrentNoteCV); - SetOutput(1,n,m_CurrentTriggerCV); + m_Time+=Speed*m_SpeedMod; - if (m_Time>m_Length) + // deal with the beat calculation + if (m_Time>m_NextBeatTime) + { + float BeatTime=m_BarLength/m_BeatsPerBar; + m_NextBeatTime=m_Time+BeatTime; + if (m_BeatLevel!=1.0f) m_BeatLevel=1.0f; + else m_BeatLevel=-1.0f; + + m_BeatCount++; + } + SetOutput(NUM_CHANNELS*2,n,m_BeatLevel); + + if (m_BeatCount>=m_BeatsPerBar) + { + m_BeatCount=0; + m_BarCount++; + } + + if (m_BarCount>=m_Length) { m_Time=0; + m_BeatCount=-1; + m_BarCount=0; + m_NextBeatTime=0; } if (m_Time<0) @@ -211,6 +677,68 @@ void SequencerPlugin::Execute() void SequencerPlugin::ExecuteCommands() { + if (m_AudioCH->IsCommandWaiting()) + { + switch (m_AudioCH->GetCommand()) + { + case NEW_NOTE : m_Track.AddNote(m_GUIArgs.Num,m_GUIArgs.Sequence,m_GUIArgs.t,m_GUIArgs.l,m_GUIArgs.n,m_GUIArgs.v); break; + case CHG_NOTE : m_Track.ChangeNote(m_GUIArgs.Num,m_GUIArgs.Sequence,m_GUIArgs.t,m_GUIArgs.l,m_GUIArgs.n,m_GUIArgs.v); break; + case REM_NOTE : m_Track.RemoveNote(m_GUIArgs.Num,m_GUIArgs.Sequence); break; + case NEW_SEQ : + { + m_Track.AddSequence(m_GUIArgs.Num); + m_Track.GetSequence(m_GUIArgs.Num)->SetColour(m_GUIArgs.Num2); + m_Track.GetSequence(m_GUIArgs.Num)->SetName(m_GUIArgs.Name); + m_Track.GetSequence(m_GUIArgs.Num)->SetLength(m_GUIArgs.l); + m_Track.GetSequence(m_GUIArgs.Num)->SetYPos(m_GUIArgs.n); + m_Track.GetSequence(m_GUIArgs.Num)->SetChannel(m_GUIArgs.Channel); + } break; + case COPY_SEQ : m_Track.CopySequence(m_GUIArgs.Num,m_GUIArgs.Num2); break; + case INST_SEQ : m_Track.InstanceSequence(m_GUIArgs.Num); break; + case CLONE_SEQ : m_Track.CloneSequence(m_GUIArgs.Num,m_GUIArgs.Num2); break; + case REM_SEQ : m_Track.RemoveSequence(m_GUIArgs.Num); break; + case CHG_SEQ : + { + m_Track.GetSequence(m_GUIArgs.Num)->SetColour(m_GUIArgs.Num2); + m_Track.GetSequence(m_GUIArgs.Num)->SetName(m_GUIArgs.Name); + m_Track.GetSequence(m_GUIArgs.Num)->SetLength(m_GUIArgs.l); + m_Track.GetSequence(m_GUIArgs.Num)->SetYPos(m_GUIArgs.n); + m_Track.GetSequence(m_GUIArgs.Num)->SetChannel(m_GUIArgs.Channel); + m_Track.GetSequence(m_GUIArgs.Num)->SetStartTime(m_GUIArgs.t); + } break; + case GET_PATTERN : + { + // start of transfer + if (m_TransferPattern==-1) + { + m_TransferPattern=m_Track.GetSequence(m_GUIArgs.Num)->GetPatternID(); + m_TransferNote=m_Track.GetPattern(m_TransferPattern)->m_NoteMap.begin(); + m_TransferCount=m_Track.GetPattern(m_TransferPattern)->GetNoteCount(); + + cerr<<"going to transfer "<m_NoteMap.end()) + { + m_TransferPattern=-1; + } + else + { + // copy this note over + m_Transfer.Time = m_TransferNote->second.Time; + m_Transfer.Length = m_TransferNote->second.Length; + m_Transfer.MidiNote = m_TransferNote->second.MidiNote; + m_Transfer.Vol = m_TransferNote->second.Vol; + + m_TransferNote++; + } + } + } break; + default: break; + } + } } void SequencerPlugin::StreamOut(ostream &s) @@ -219,23 +747,10 @@ void SequencerPlugin::StreamOut(ostream &s) switch (m_Version) { - case 2: - { - s<>m_Time; - s>>m_Length; - s>>m_SpeedMod; - s>>m_Loop; - s>>m_NoteCut; - s>>m_CurrentPattern; - } - // fallthrough - case 1: { - for(int n=0; n>*m_Eventmap[n]; - } + s>>m_Time>>m_Length>>m_BarLength>>m_BeatsPerBar; + s>>m_Track; } break; } } diff --git a/SpiralSound/Plugins/SequencerPlugin/SequencerPlugin.h b/SpiralSound/Plugins/SequencerPlugin/SequencerPlugin.h index 621c843..2c52b8a 100644 --- a/SpiralSound/Plugins/SequencerPlugin/SequencerPlugin.h +++ b/SpiralSound/Plugins/SequencerPlugin/SequencerPlugin.h @@ -24,36 +24,127 @@ #ifndef SequencerPLUGIN #define SequencerPLUGIN -const int NUM_PATTERNS = 16; +const int NUM_PATTERNS = 8; +const int NUM_CHANNELS = 8; + +////////////////////////////////////////////////////////////////////////// +// base sequencing stuff + +class Note +{ +public: + Note(float t, float l, int n, float v); + virtual ~Note(); + + float Time; + float Length; + int MidiNote; + float Vol; + + friend istream &operator>>(istream &s, Note &o); + friend ostream &operator<<(ostream &s, Note &o); +}; + +istream &operator>>(istream &s, Note &o); +ostream &operator<<(ostream &s, Note &o); + +class Pattern +{ +public: + Pattern(); + virtual ~Pattern(); + + void Copy(const Pattern *o); + void AddNote(int ID, float t, float l, int n, float v); + void RemoveNote(int ID); + Note *GetNote(int ID); + int GetNoteCount() { return m_NoteMap.size(); } + + map m_NoteMap; + + friend istream &operator>>(istream &s, Pattern &o); + friend ostream &operator<<(ostream &s, Pattern &o); +}; + +istream &operator>>(istream &s, Pattern &o); +ostream &operator<<(ostream &s, Pattern &o); + +class Sequence +{ +public: + Sequence(float st=0, int pat=0); + virtual ~Sequence(); + + void SetStartTime(float t) { m_StartTime=t; } + float GetStartTime() { return m_StartTime; } + void SetPatternID(int p) { m_Pattern=p; } + int GetPatternID() { return m_Pattern; } + void SetName(string s) { m_Name=s; } + string GetName() { return m_Name; } + void SetColour(int s) { m_Colour=s; } + int GetColour() { return m_Colour; } + void SetYPos(int s) { m_YPos=s; } + int GetYPos() { return m_YPos; } + void SetLength(float t) { m_Length=t; } + float GetLength() { return m_Length; } + void SetChannel(int s) { m_Channel=s; } + int GetChannel() { return m_Channel; } + +private: + float m_StartTime; + int m_Pattern; + string m_Name; + int m_Colour; + int m_YPos; + float m_Length; + int m_Channel; + + friend istream &operator>>(istream &s, Sequence &o); + friend ostream &operator<<(ostream &s, Sequence &o); +}; + +istream &operator>>(istream &s, Sequence &o); +ostream &operator<<(ostream &s, Sequence &o); class Track { public: - class Sequence - { - public: - class Pattern - { - public: - class Note - { - public: - float time; - int note; - float vol; - }; - - map m_NoteMap; - }; + Track(); + virtual ~Track(); + + void AddSequence(int ID); + void CloneSequence(int ID, int nID); + void CopySequence(int ID, int nID); + void InstanceSequence(int ID); + void RemoveSequence(int ID); + Sequence *GetSequence(int ID); - float m_StartTime; - int m_Pattern; - }; + void AddNote(int ID, int Sequence, float t, float l, int n, float v); + void RemoveNote(int ID, int Sequence); + void ChangeNote(int ID, int Sequence, float t, float l, int n, float v); + void ReadTrack(float t, int channel, vector &NoteVec); + Pattern *GetPattern(int ID); + + map *GetSequenceMap() { return &m_SequenceMap; } + +private: + void AddPattern(int ID); + void RemovePattern(int ID); + + map m_PatternMap; + map m_SequenceMap; + + int m_NextPatternID; - map m_PatternMap; - list m_SequenceList; + friend istream &operator>>(istream &s, Track &o); + friend ostream &operator<<(ostream &s, Track &o); }; +istream &operator>>(istream &s, Track &o); +ostream &operator<<(ostream &s, Track &o); + +/////////////////////////////////////////////////////////////////////////// + class SequencerPlugin : public SpiralPlugin { public: @@ -70,26 +161,56 @@ public: bool GetNoteCut() { return m_NoteCut; } void ClearAll() { /*m_Eventmap[m_CurrentPattern]->RemoveAllEvents();*/ } int GetCurrentPattern() { return m_CurrentPattern; } + Track *GetTrack() { return &m_Track; } + + enum GUICommands {NONE,NEW_NOTE,REM_NOTE,CHG_NOTE,NEW_SEQ,CHG_SEQ,COPY_SEQ, + INST_SEQ,CLONE_SEQ,REM_SEQ,GET_PATTERN}; + + struct GUIArgs + { + int Num,Num2; + int Sequence; + float t,l,v; + int n; + char Name[256]; + int Channel; + }; private: + GUIArgs m_GUIArgs; + Track m_Track; + int m_TransferPattern; + //int m_TransferNote; + map::iterator m_TransferNote; + int m_TransferCount; + Note m_Transfer; + void SetEventMap(int n, Fl_EventMap* s) { /*m_Eventmap[n]=s;*/ } void SetUpdate(bool s) { /*m_Eventmap[m_CurrentPattern]->SetUpdate(s);*/ } void SetZoom(float s) { /*m_Eventmap[m_CurrentPattern]->SetZoomLevel(s);*/ } void SetNoteCut(bool s) { m_NoteCut=s; } - void SetEndTime(float s) { /*m_Eventmap[m_CurrentPattern]->SetEndTime(s);*/ m_Length=s; } + //void SetEndTime(float s) { /*m_Eventmap[m_CurrentPattern]->SetEndTime(s);*/ m_Length=s; } void SetSpeed(float s) { m_SpeedMod=s; } void SetPattern(int s); float m_Time; - float m_Length; + int m_Length; // in bars + float m_BarLength; + int m_BeatsPerBar; + float m_NextBeatTime; + float m_BeatLevel; + int m_BeatCount; + int m_BarCount; bool m_Loop; bool m_NoteCut; float m_SpeedMod; - float m_CurrentNoteCV; - float m_CurrentTriggerCV; + + float m_CurrentNoteCV[NUM_CHANNELS]; + float m_CurrentTriggerCV[NUM_CHANNELS]; + bool m_InNoteDown; int m_InNoteID; float m_InNoteTime; diff --git a/SpiralSound/Plugins/SequencerPlugin/SequencerPluginGUI.C b/SpiralSound/Plugins/SequencerPlugin/SequencerPluginGUI.C index 1939371..29f8a5e 100644 --- a/SpiralSound/Plugins/SequencerPlugin/SequencerPluginGUI.C +++ b/SpiralSound/Plugins/SequencerPlugin/SequencerPluginGUI.C @@ -21,6 +21,7 @@ #include #include #include +#include static const int GUI_COLOUR = 179; static const int GUIBG_COLOUR = 144; @@ -34,14 +35,23 @@ Fl_Double_Window(w,h,n) m_Scroll = new Fl_Scroll(0, 0, w, h, ""); resizable(m_Scroll); add(m_Scroll); + m_NextNoteID=0; m_Melody = new Fl_EventMap(0, 0, 1000, 1000, ""); m_Melody->SetType(Fl_EventMap::MELODY_MAP); m_Scroll->add(m_Melody); + m_Scroll->position(0,350); m_Melody->CreateWindow(); - m_Melody->SetUpdateLineClip(0, 18, w, h-38); m_Melody->show(); + // callbacks for note events + Fl_EventMap::EventCallbacks cb; + cb.cb_NewEvent=(Fl_Callback*)cb_NewNote; + cb.cb_MoveEvent=(Fl_Callback*)cb_MoveNote; + cb.cb_DelEvent=(Fl_Callback*)cb_RemoveNote; + + m_Melody->SetCallbacks(cb); + end(); } @@ -52,25 +62,56 @@ SpiralPluginGUI(w,h,o,ch) { m_Scroll = new Fl_Scroll(50, 20, w-57, h-26, ""); add(m_Scroll); - - m_ArrangementMap = new Fl_EventMap(0, 0, 1000, 1000, ""); + m_ArrangementMap = new Fl_EventMap(0, 0, 1000, 132*10, ""); + // num midi notes * gridsize y ^ m_ArrangementMap->user_data((void*)this); m_ArrangementMap->SetType(Fl_EventMap::ARRANGE_MAP); m_Scroll->add(m_ArrangementMap); + m_Scroll->position(-50,350); m_ArrangementMap->CreateWindow(); - m_ArrangementMap->SetUpdateLineClip(0, 18, w, h-38); + m_ArrangementMap->SetZoomLevel(3.0f); m_ArrangementMap->show(); - - m_Length = new Fl_Knob(5, 60, 40, 40, "Length"); - m_Length->color(GUI_COLOUR); - m_Length->type(Fl_Knob::DOTLIN); - m_Length->labelsize(10); - m_Length->maximum(30); - m_Length->step(0.01); - m_Length->value(1.0); + + // callbacks for sequence events + Fl_EventMap::EventCallbacks cb; + cb.cb_EventDoubleClicked=(Fl_Callback*)cb_ArrangeRM; + cb.cb_MoveEvent=(Fl_Callback*)cb_MoveSequence; + cb.cb_RenameEvent=(Fl_Callback*)cb_Rename; + cb.cb_Recolour=(Fl_Callback*)cb_Recolour; + cb.cb_CopyEvent=(Fl_Callback*)cb_Copy; + cb.cb_DelEvent=(Fl_Callback*)cb_RemoveSequence; + cb.cb_EditEvent=(Fl_Callback*)cb_Edit; + + m_ArrangementMap->SetCallbacks(cb); + + m_Length = new Fl_Input(12, 15, 24, 12, "LengthBars"); + m_Length->color(GUI_COLOUR); + m_Length->labelsize(8); + m_Length->align(FL_ALIGN_BOTTOM|FL_ALIGN_CENTER); + m_Length->textsize(8); + m_Length->value("4"); m_Length->callback((Fl_Callback*)cb_Length); add(m_Length); + m_BeatsPerBar = new Fl_Input(12, 38, 24, 12, "BeatsPerBar"); + m_BeatsPerBar->color(GUI_COLOUR); + m_BeatsPerBar->labelsize(8); + m_BeatsPerBar->align(FL_ALIGN_BOTTOM|FL_ALIGN_CENTER); + m_BeatsPerBar->textsize(8); + m_BeatsPerBar->value("4"); + m_BeatsPerBar->callback((Fl_Callback*)cb_BeatsPerBar); + add(m_BeatsPerBar); + + m_BarLength = new Fl_Knob(5, 60, 40, 40, "BarLength"); + m_BarLength->color(GUI_COLOUR); + m_BarLength->type(Fl_Knob::DOTLIN); + m_BarLength->labelsize(10); + m_BarLength->maximum(10); + m_BarLength->step(0.01); + m_BarLength->value(1.0); + m_BarLength->callback((Fl_Callback*)cb_BarLength); + add(m_BarLength); + m_Speed = new Fl_Knob(5, 115, 40, 40, "Speed"); m_Speed->color(GUI_COLOUR); m_Speed->type(Fl_Knob::DOTLIN); @@ -85,9 +126,9 @@ SpiralPluginGUI(w,h,o,ch) m_Zoom->color(GUI_COLOUR); m_Zoom->type(Fl_Knob::DOTLIN); m_Zoom->labelsize(10); - m_Zoom->maximum(2); + m_Zoom->maximum(6); m_Zoom->step(0.01); - m_Zoom->value(1.0); + m_Zoom->value(3.0); m_Zoom->callback((Fl_Callback*)cb_Zoom); add(m_Zoom); @@ -114,10 +155,94 @@ SpiralPluginGUI(w,h,o,ch) end(); } +void SequencerPluginGUI::LoadPatternData(int ID) +{ + Note note(0,1.0f,0,0); + + m_PatternWinMap[ID]->GetEventMap()->RemoveAllEvents(); + + m_GUICH->Wait(); + m_GUICH->Set("ID",ID); + m_GUICH->SetCommand(SequencerPlugin::GET_PATTERN); + m_GUICH->Wait(); + + m_GUICH->RequestChannelAndWait("TransCount"); + int c = m_GUICH->GetInt("TransCount"); + cerr<<"TransCount="<SetCommand(SequencerPlugin::GET_PATTERN); + m_GUICH->RequestChannelAndWait("TransNote"); + m_GUICH->GetData("TransNote",(void*)¬e); + + cerr<<"Adding note "<GetEventMap()->AddEventTime(note.Time,note.MidiNote,note.Length,Fl_SEvent::MELODY,false); + } +} + void SequencerPluginGUI::UpdateValues(SpiralPlugin *o) { + SequencerPlugin *Plugin = (SequencerPlugin *)o; + Track *t = Plugin->GetTrack(); + map *seqmap=t->GetSequenceMap(); + map::iterator pi; + + // for each sequence + for (map::iterator i=seqmap->begin(); + i!=seqmap->end(); i++) + { + int eid = m_ArrangementMap->AddEventTime(i->second.GetStartTime(),i->second.GetYPos(),i->second.GetLength(),Fl_SEvent::NO_TYPE,false); + m_ArrangementMap->GetEvent(eid)->SetName(i->second.GetName()); + m_ArrangementMap->GetEvent(eid)->SetColour(i->second.GetColour()); + m_ArrangementMap->GetEvent(eid)->SetChannel(i->second.GetChannel()); + m_ArrangementMap->GetEvent(eid)->SetLengthTime(i->second.GetLength()); + m_PatternWinMap[eid] = new PatternWin(400,200,m_ArrangementMap->GetEvent(eid)->GetName().c_str()); + + Fl_EventMap *map = m_PatternWinMap[eid]->GetEventMap(); + map->user_data((void*)this); + map->SetID(eid); + + // load the pattern data + Pattern *p = t->GetPattern(i->second.GetPatternID()); + + for (pi=p->m_NoteMap.begin(); + pi!=p->m_NoteMap.end(); pi++) + { + map->AddEventTime(pi->second.Time,pi->second.MidiNote,pi->second.Length,Fl_SEvent::MELODY,false); + } + } + + redraw(); } +void SequencerPluginGUI::Update() +{ + float Time=m_GUICH->GetFloat("CurrentTime"); + m_ArrangementMap->SetTime(Time); + + for (map::iterator i=m_PatternWinMap.begin(); + i!=m_PatternWinMap.end(); i++) + { + i->second->GetEventMap()->SetTime(Time); + } +} + +void SequencerPluginGUI::ChangeSequenceHelper(Fl_SEvent *event) +{ + m_GUICH->Set("ID",event->GetID()); + m_GUICH->Set("ID2",event->GetColour()); + char t[256]; + sprintf(t,"%s",event->GetName().c_str()); + m_GUICH->SetData("Name",(void*)t); + m_GUICH->Set("Length",event->GetLengthTime()); + m_GUICH->Set("Note",event->GetGroup()); + m_GUICH->Set("Channel",event->GetChannel()); + m_GUICH->Set("Time",event->GetStartTime()); + m_GUICH->SetCommand(SequencerPlugin::CHG_SEQ); +} + inline void SequencerPluginGUI::cb_NoteCut_i(Fl_Button* o, void* v) { //m_Plugin->SetNoteCut(o->value()); @@ -127,7 +252,7 @@ void SequencerPluginGUI::cb_NoteCut(Fl_Button* o, void* v) inline void SequencerPluginGUI::cb_Zoom_i(Fl_Knob* o, void* v) { - //m_Plugin->SetZoom(o->value()); + if (o->value()!=0) m_ArrangementMap->SetZoomLevel(o->value()); } void SequencerPluginGUI::cb_Zoom(Fl_Knob* o, void* v) { ((SequencerPluginGUI*)(o->parent()))->cb_Zoom_i(o,v);} @@ -144,13 +269,60 @@ inline void SequencerPluginGUI::cb_Pattern_i(Fl_Counter* o, void* v) void SequencerPluginGUI::cb_Pattern(Fl_Counter* o, void* v) { ((SequencerPluginGUI*)(o->parent()))->cb_Pattern_i(o,v);} -inline void SequencerPluginGUI::cb_Length_i(Fl_Knob* o, void* v) +inline void SequencerPluginGUI::cb_Length_i(Fl_Input* o, void* v) { - //m_Plugin->SetEndTime(o->value()); + int val=(int)strtod(o->value(),NULL); + if (val<1) o->value("error!"); + else + { + m_GUICH->Set("TotalLength",val); + } } -void SequencerPluginGUI::cb_Length(Fl_Knob* o, void* v) +void SequencerPluginGUI::cb_Length(Fl_Input* o, void* v) { ((SequencerPluginGUI*)(o->parent()))->cb_Length_i(o,v);} +inline void SequencerPluginGUI::cb_BeatsPerBar_i(Fl_Input* o, void* v) +{ + int val=(int)strtod(o->value(),NULL); + if (val<1) o->value("error!"); + else + { + m_GUICH->Set("BeatsPerBar",val); + m_ArrangementMap->SetBeatsBar(val); + m_ArrangementMap->redraw(); + + for (map::iterator i=m_PatternWinMap.begin(); + i!=m_PatternWinMap.end(); i++) + { + i->second->GetEventMap()->SetBeatsBar(val); + i->second->GetEventMap()->redraw(); + } + } +} +void SequencerPluginGUI::cb_BeatsPerBar(Fl_Input* o, void* v) +{ ((SequencerPluginGUI*)(o->parent()))->cb_BeatsPerBar_i(o,v);} + +inline void SequencerPluginGUI::cb_BarLength_i(Fl_Knob* o, void* v) +{ + if (o->value()!=0) + { + m_GUICH->Set("BarLength",(float)o->value()); + m_ArrangementMap->SetBarLength(o->value()); + m_ArrangementMap->redraw(); + + for (map::iterator i=m_PatternWinMap.begin(); + i!=m_PatternWinMap.end(); i++) + { + i->second->GetEventMap()->SetBarLength(o->value()); + i->second->GetEventMap()->redraw(); + } + + redraw(); + } +} +void SequencerPluginGUI::cb_BarLength(Fl_Knob* o, void* v) +{ ((SequencerPluginGUI*)(o->parent()))->cb_BarLength_i(o,v);} + inline void SequencerPluginGUI::cb_Speed_i(Fl_Knob* o, void* v) { //m_Plugin->SetSpeed(o->value()-2.0f); @@ -165,20 +337,110 @@ inline void SequencerPluginGUI::cb_Clear_i(Fl_Button* o, void* v) void SequencerPluginGUI::cb_Clear(Fl_Button* o, void* v) { ((SequencerPluginGUI*)(o->parent()))->cb_Clear_i(o,v);} +/// sequence callbacks ///////////////////////////////////////////////////////// + inline void SequencerPluginGUI::cb_NewPattern_i(Fl_Button* o, void* v) { - int eid = m_ArrangementMap->AddEvent(300,100,100,Fl_SEvent::NO_TYPE); + int eid = m_ArrangementMap->AddEventTime(1,50,2,Fl_SEvent::NO_TYPE); m_ArrangementMap->GetEvent(eid)->SetName("My Pattern"); - const char *name = fl_input("Name the new pattern:", "My Pattern"); - if (name) m_ArrangementMap->GetEvent(eid)->SetName(name); m_PatternWinMap[eid] = new PatternWin(400,200,m_ArrangementMap->GetEvent(eid)->GetName().c_str()); - m_ArrangementMap->SetEventCallback((Fl_Callback*)cb_ArrangeRM); + Fl_EventMap *map = m_PatternWinMap[eid]->GetEventMap(); + Fl_SEvent *event = m_ArrangementMap->GetEvent(eid); + + // setup the stuff needed by the callbacks + map->user_data((void*)this); + map->SetID(eid); + + m_GUICH->Set("ID",eid); + m_GUICH->Set("ID2",event->GetColour()); + char t[256]; + sprintf(t,"%s",event->GetName().c_str()); + m_GUICH->SetData("Name",(void*)t); + m_GUICH->Set("Length",event->GetLengthTime()); + m_GUICH->Set("Channel",event->GetChannel()); + m_GUICH->Set("Note",event->GetGroup()); + m_GUICH->SetCommand(SequencerPlugin::NEW_SEQ); + redraw(); } void SequencerPluginGUI::cb_NewPattern(Fl_Button* o, void* v) { ((SequencerPluginGUI*)(o->parent()))->cb_NewPattern_i(o,v);} +inline void SequencerPluginGUI::cb_Rename_i(Fl_Widget* o, void* v) +{ + Fl_SEvent *event = ((Fl_SEvent*)v); + + const char *name = fl_input("Rename the sequence:", + m_ArrangementMap->GetEvent(event->GetID())->GetName().c_str()); + if (name) m_ArrangementMap->GetEvent(event->GetID())->SetName(name); + + ChangeSequenceHelper(event); + redraw(); +} + +void SequencerPluginGUI::cb_Rename(Fl_Widget* o, void* v) +{ ((SequencerPluginGUI*)(o->parent()->parent()->user_data()))->cb_Rename_i(o,v);} + +inline void SequencerPluginGUI::cb_Recolour_i(Fl_Widget* o, void* v) +{ + Fl_SEvent *event = ((Fl_SEvent*)v); + + unsigned char r=255,g=255,b=255; + if (fl_color_chooser("colour",r,g,b)) + { + fl_color(r,g,b); + Fl_Color col=fl_color(); + m_ArrangementMap->GetEvent(event->GetID())->SetColour(col); + ChangeSequenceHelper(event); + redraw(); + } +} +void SequencerPluginGUI::cb_Recolour(Fl_Widget* o, void* v) +{ ((SequencerPluginGUI*)(o->parent()->parent()->user_data()))->cb_Recolour_i(o,v);} + +inline void SequencerPluginGUI::cb_RemoveSequence_i(Fl_Widget* o, void* v) +{ + Fl_SEvent *event = ((Fl_SEvent*)v); + Fl_EventMap *map = ((Fl_EventMap*)event->parent()); + + event->KillMe(); + map->redraw(); + + m_GUICH->Set("ID",event->GetID()); + m_GUICH->SetCommand(SequencerPlugin::REM_SEQ); +} +void SequencerPluginGUI::cb_RemoveSequence(Fl_Widget* o, void* v) +{ ((SequencerPluginGUI*)(o->parent()->parent()->user_data()))->cb_RemoveSequence_i(o,v);} + +inline void SequencerPluginGUI::cb_Copy_i(Fl_Widget* o, void* v) +{ + Fl_SEvent *event = ((Fl_SEvent*)v); + int NewID = m_ArrangementMap->CopyEvent(event->x()+event->w(),event->y(),event->w(),event->GetID(), event->GetLengthTime()); + + m_PatternWinMap[NewID] = new PatternWin(400,200,m_ArrangementMap->GetEvent(NewID)->GetName().c_str()); + m_PatternWinMap[NewID]->GetEventMap()->user_data((void*)this); + m_PatternWinMap[NewID]->GetEventMap()->SetID(NewID); + + m_GUICH->Set("ID",event->GetID()); + m_GUICH->Set("ID2",NewID); + + m_GUICH->SetCommand(SequencerPlugin::COPY_SEQ); + + LoadPatternData(NewID); +} +void SequencerPluginGUI::cb_Copy(Fl_Widget* o, void* v) +{ ((SequencerPluginGUI*)(o->parent()->parent()->user_data()))->cb_Copy_i(o,v);} + +inline void SequencerPluginGUI::cb_MoveSequence_i(Fl_Widget* o, void* v) +{ + Fl_SEvent *event = ((Fl_SEvent*)o); + m_PatternWinMap[event->GetID()]->GetEventMap()->SetTimeOffset(event->GetStartTime()); + ChangeSequenceHelper(event); +} +void SequencerPluginGUI::cb_MoveSequence(Fl_Widget* o, void* v) +{ ((SequencerPluginGUI*)(o->parent()->user_data()))->cb_MoveSequence_i(o,v);} + inline void SequencerPluginGUI::cb_ArrangeRM_i(Fl_Button* o, void* v) { int ID=((Fl_SEvent*)o)->GetID(); @@ -188,4 +450,83 @@ inline void SequencerPluginGUI::cb_ArrangeRM_i(Fl_Button* o, void* v) } void SequencerPluginGUI::cb_ArrangeRM(Fl_Button* o, void* v) { ((SequencerPluginGUI*)(o->parent()->user_data()))->cb_ArrangeRM_i(o,v);} +#include +inline void SequencerPluginGUI::cb_Edit_i(Fl_Widget* o, void* v) +{ + Fl_SEvent *event = ((Fl_SEvent*)v); + + Fl_Double_Window *EditWin = new Fl_Double_Window(100,100,"Properties"); + Fl_Button *exit = new Fl_Button(10,80,80,10,"Exit"); + exit->labelsize(8); + Fl_Counter *channel = new Fl_Counter(5,10,90,20,"Channel"); + channel->labelsize(8); + channel->textsize(8); + channel->type(FL_SIMPLE_COUNTER); + channel->step(1); + channel->value(event->GetChannel()); + EditWin->show(); + while (!exit->value() || !EditWin->shown()) + { + Fl::check(); + usleep(10000); + } + event->SetChannel((int)channel->value()); + ChangeSequenceHelper(event); + redraw(); + + EditWin->hide(); +} +void SequencerPluginGUI::cb_Edit(Fl_Widget* o, void* v) +{ ((SequencerPluginGUI*)(o->parent()->parent()->user_data()))->cb_Edit_i(o,v);} + +/// note callbacks /////////////////////////////////////////////////////////////// + +inline void SequencerPluginGUI::cb_NewNote_i(Fl_Widget* o, void* v) +{ + Fl_SEvent *event = ((Fl_SEvent*)o); + Fl_EventMap *map = ((Fl_EventMap*)o->parent()); + + m_GUICH->Set("ID",event->GetID()); + m_GUICH->Set("Sequence",map->GetID()); + m_GUICH->Set("Time",event->GetStartTime()); + m_GUICH->Set("Length",event->GetLengthTime()); + m_GUICH->Set("Note",event->GetGroup()); + m_GUICH->Set("Vol",1.0f); + + m_GUICH->SetCommand(SequencerPlugin::NEW_NOTE); +} +void SequencerPluginGUI::cb_NewNote(Fl_Widget* o, void* v) +{ ((SequencerPluginGUI*)(o->parent()->user_data()))->cb_NewNote_i(o,v);} + +inline void SequencerPluginGUI::cb_MoveNote_i(Fl_Widget* o, void* v) +{ + Fl_SEvent *event = ((Fl_SEvent*)o); + Fl_EventMap *map = ((Fl_EventMap*)o->parent()); + + m_GUICH->Set("ID",event->GetID()); + m_GUICH->Set("Sequence",map->GetID()); + m_GUICH->Set("Time",event->GetStartTime()); + m_GUICH->Set("Length",event->GetLengthTime()); + m_GUICH->Set("Note",event->GetGroup()); + m_GUICH->Set("Vol",1.0f); + + m_GUICH->SetCommand(SequencerPlugin::CHG_NOTE); +} +void SequencerPluginGUI::cb_MoveNote(Fl_Widget* o, void* v) +{ ((SequencerPluginGUI*)(o->parent()->user_data()))->cb_MoveNote_i(o,v);} + +inline void SequencerPluginGUI::cb_RemoveNote_i(Fl_Widget* o, void* v) +{ + Fl_SEvent *event = ((Fl_SEvent*)v); + Fl_EventMap *map = ((Fl_EventMap*)event->parent()); + + event->KillMe(); + map->redraw(); + + m_GUICH->Set("ID",event->GetID()); + m_GUICH->Set("Sequence",map->GetID()); + m_GUICH->SetCommand(SequencerPlugin::REM_NOTE); +} +void SequencerPluginGUI::cb_RemoveNote(Fl_Widget* o, void* v) +{ ((SequencerPluginGUI*)(o->parent()->parent()->user_data()))->cb_RemoveNote_i(o,v);} diff --git a/SpiralSound/Plugins/SequencerPlugin/SequencerPluginGUI.h b/SpiralSound/Plugins/SequencerPlugin/SequencerPluginGUI.h index adedacd..ca0d06e 100644 --- a/SpiralSound/Plugins/SequencerPlugin/SequencerPluginGUI.h +++ b/SpiralSound/Plugins/SequencerPlugin/SequencerPluginGUI.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "SequencerPlugin.h" #include "../SpiralPluginGUI.h" @@ -39,6 +40,7 @@ public: SequencerPluginGUI(int w, int h, SequencerPlugin *o, ChannelHandler *ch,const HostInfo *Info); virtual void UpdateValues(SpiralPlugin *o); + virtual void Update(); private: @@ -46,23 +48,34 @@ private: Fl_Button* m_NewPattern; Fl_Button* m_NoteCut; Fl_Knob* m_Zoom; - Fl_Knob* m_Length; Fl_Knob* m_Speed; Fl_Button* m_Clear; + Fl_Input* m_Length; + Fl_Input* m_BeatsPerBar; + Fl_Knob* m_BarLength; + + int m_NextPatternID; class PatternWin : public Fl_Double_Window { public: PatternWin(int w,int h,const char* n); + Fl_EventMap *GetEventMap() { return m_Melody; } private: Fl_Scroll* m_Scroll; Fl_EventMap* m_Melody; + int m_NextNoteID; }; map m_PatternWinMap; Fl_EventMap* m_ArrangementMap; + // get the notes from the audio thread + void LoadPatternData(int ID); + + void ChangeSequenceHelper(Fl_SEvent *event); + //// Callbacks //// inline void cb_Zoom_i(Fl_Knob* o, void* v); static void cb_Zoom(Fl_Knob* o, void* v); @@ -70,8 +83,12 @@ private: static void cb_NoteCut(Fl_Button* o, void* v); inline void cb_Pattern_i(Fl_Counter* o, void* v); static void cb_Pattern(Fl_Counter* o, void* v); - inline void cb_Length_i(Fl_Knob* o, void* v); - static void cb_Length(Fl_Knob* o, void* v); + inline void cb_Length_i(Fl_Input* o, void* v); + static void cb_Length(Fl_Input* o, void* v); + inline void cb_BeatsPerBar_i(Fl_Input* o, void* v); + static void cb_BeatsPerBar(Fl_Input* o, void* v); + inline void cb_BarLength_i(Fl_Knob* o, void* v); + static void cb_BarLength(Fl_Knob* o, void* v); inline void cb_Speed_i(Fl_Knob* o, void* v); static void cb_Speed(Fl_Knob* o, void* v); inline void cb_Clear_i(Fl_Button* o, void* v); @@ -79,8 +96,29 @@ private: inline void cb_NewPattern_i(Fl_Button* o, void* v); static void cb_NewPattern(Fl_Button* o, void* v); + // sequence event callbacks inline void cb_ArrangeRM_i(Fl_Button* o, void* v); static void cb_ArrangeRM(Fl_Button* o, void* v); + inline void cb_MoveSequence_i(Fl_Widget* o, void* v); + static void cb_MoveSequence(Fl_Widget* o, void* v); + inline void cb_Rename_i(Fl_Widget* o, void* v); + static void cb_Rename(Fl_Widget* o, void* v); + inline void cb_Recolour_i(Fl_Widget* o, void* v); + static void cb_Recolour(Fl_Widget* o, void* v); + inline void cb_Copy_i(Fl_Widget* o, void* v); + static void cb_Copy(Fl_Widget* o, void* v); + inline void cb_RemoveSequence_i(Fl_Widget* o, void* v); + static void cb_RemoveSequence(Fl_Widget* o, void* v); + inline void cb_Edit_i(Fl_Widget* o, void* v); + static void cb_Edit(Fl_Widget* o, void* v); + + // note event callbacks + inline void cb_NewNote_i(Fl_Widget* o, void* v); + static void cb_NewNote(Fl_Widget* o, void* v); + inline void cb_MoveNote_i(Fl_Widget* o, void* v); + static void cb_MoveNote(Fl_Widget* o, void* v); + inline void cb_RemoveNote_i(Fl_Widget* o, void* v); + static void cb_RemoveNote(Fl_Widget* o, void* v); }; #endif