summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Jonsson <spamatica@gmail.com>2012-09-30 21:53:03 +0000
committerRobert Jonsson <spamatica@gmail.com>2012-09-30 21:53:03 +0000
commite1a3d5b87883b5faadbd43326326d4c5aadc871d (patch)
treeecbb1a0aa3d5e05039ac5d08ad57bc1d056f072e
parent6db72b766ea8bf781d0172a62f873104b2e7cab6 (diff)
various fixes and changes
-rw-r--r--muse2/ChangeLog6
-rw-r--r--muse2/muse/arranger/pcanvas.cpp41
-rw-r--r--muse2/muse/arranger/tlist.cpp40
-rw-r--r--muse2/muse/audiotrack.cpp42
-rw-r--r--muse2/muse/functions.cpp97
-rw-r--r--muse2/muse/functions.h6
-rw-r--r--muse2/muse/mixer/astrip.cpp6
-rw-r--r--muse2/muse/mixer/strip.cpp6
-rw-r--r--muse2/muse/song.h1
-rw-r--r--muse2/muse/track.h3
-rw-r--r--muse2/muse/waveedit/wavecanvas.cpp43
-rw-r--r--muse2/muse/waveedit/wavecanvas.h1
-rw-r--r--muse2/muse/waveedit/waveedit.cpp4
-rw-r--r--muse2/muse/waveedit/waveedit.h1
14 files changed, 228 insertions, 69 deletions
diff --git a/muse2/ChangeLog b/muse2/ChangeLog
index a8b29d58..a7c185c1 100644
--- a/muse2/ChangeLog
+++ b/muse2/ChangeLog
@@ -1,3 +1,9 @@
+30.09.2012:
+ - Added part creation from wave editor - to make this really usable
+ more functions to set tempo etc, are needed (rj)
+ - Fixed name length of Aux ports and added index (rj)
+ - Fixed issue with moving aux:es in the track list causing the auxes
+ to be mixed up (rj)
29.09.2012:
- Added handling of missing soundfonts in fluidsynth load so
a dialog asking for replacement soundfont pops up (rj)
diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp
index 1afea012..3c3e6116 100644
--- a/muse2/muse/arranger/pcanvas.cpp
+++ b/muse2/muse/arranger/pcanvas.cpp
@@ -2829,40 +2829,13 @@ void PartCanvas::copy(MusECore::PartList* pl)
}
MusECore::Pos p(tick, true);
MusEGlobal::song->setPos(0, p);
-
- //---------------------------------------------------
- // read tmp file into QTextDrag Object
- //---------------------------------------------------
-
- fflush(tmp);
- struct stat f_stat;
- if (fstat(fileno(tmp), &f_stat) == -1) {
- fprintf(stderr, "PartCanvas::copy() fstat failed:<%s>\n",
- strerror(errno));
- fclose(tmp);
- return;
- }
- int n = f_stat.st_size;
- char* fbuf = (char*)mmap(0, n+1, PROT_READ|PROT_WRITE,
- MAP_PRIVATE, fileno(tmp), 0);
- fbuf[n] = 0;
-
- QByteArray data(fbuf);
- QMimeData* md = new QMimeData();
-
-
- if(midi && wave)
- md->setData("text/x-muse-mixedpartlist", data); // By T356. Support mixed .mpt files.
- else
- if(midi)
- md->setData("text/x-muse-midipartlist", data);
- else
- if(wave)
- md->setData("text/x-muse-wavepartlist", data);
-
- QApplication::clipboard()->setMimeData(md, QClipboard::Clipboard);
-
- munmap(fbuf, n);
+ QString mimeString = "text/x-muse-mixedpartlist";
+ if (!midi)
+ mimeString = "text/x-muse-wavepartlist";
+ else if (!wave)
+ mimeString = "text/x-muse-midipartlist";
+ QMimeData *mimeData = MusECore::file_to_mimedata(tmp, mimeString );
+ QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
fclose(tmp);
}
diff --git a/muse2/muse/arranger/tlist.cpp b/muse2/muse/arranger/tlist.cpp
index 76dd18ff..d16a8d29 100644
--- a/muse2/muse/arranger/tlist.cpp
+++ b/muse2/muse/arranger/tlist.cpp
@@ -378,7 +378,11 @@ void TList::paint(const QRect& r)
}
break;
case COL_NAME:
- p.drawText(r, Qt::AlignVCenter|Qt::AlignLeft, track->name());
+ if (track->type() == MusECore::Track::AUDIO_AUX) {
+ p.drawText(r, Qt::AlignVCenter|Qt::AlignLeft, ((MusECore::AudioAux *)track)->auxName());
+ } else {
+ p.drawText(r, Qt::AlignVCenter|Qt::AlignLeft, track->name());
+ }
break;
case COL_OCHANNEL:
{
@@ -2435,8 +2439,42 @@ void TList::mouseReleaseEvent(QMouseEvent* ev)
if (t) {
int dTrack = MusEGlobal::song->tracks()->index(t);
MusEGlobal::audio->msgMoveTrack(sTrack, dTrack);
+ MusECore::TrackList *tracks = MusEGlobal::song->tracks();
+ if ( tracks->at(dTrack)->type() == MusECore::Track::AUDIO_AUX) {
+
+ MusECore::AuxList auxCopy; // = *MusEGlobal::song->auxs();
+ //MusEGlobal::song->auxs()->clear();
+ std::vector<int> oldAuxIndex;
+
+ for (MusECore::iTrack t = tracks->begin(); t != tracks->end(); ++t) {
+ if ((*t)->type() == MusECore::Track::AUDIO_AUX) {
+ MusECore::AudioAux *ax = (MusECore::AudioAux*)*t;
+ auxCopy.push_back(ax);
+ oldAuxIndex.push_back(MusEGlobal::song->auxs()->index(ax)); // store old index
+ }
+ }
+ // loop through all tracks and set the levels for all tracks
+ for (MusECore::iTrack t = tracks->begin(); t != tracks->end(); ++t) {
+ MusECore::AudioTrack *trk = (MusECore::AudioTrack*)*t;
+ if (trk->hasAuxSend())
+ {
+ std::vector<double> oldAuxValue;
+ for (unsigned i = 0 ; i < auxCopy.size(); i++)
+ oldAuxValue.push_back(trk->auxSend(i));
+ for (unsigned i = 0 ; i < auxCopy.size(); i++)
+ trk->setAuxSend(i, oldAuxValue[oldAuxIndex[i]] );
+ }
+ MusEGlobal::song->auxs()->clear();
+ for (MusECore::iAudioAux t = auxCopy.begin(); t != auxCopy.end(); ++t) {
+ MusEGlobal::song->auxs()->push_back(*t);
+ }
+ }
+
+ MusEGlobal::song->update(SC_EVERYTHING);
+
}
}
+ }
if (mode != NORMAL) {
mode = NORMAL;
setCursor(QCursor(Qt::ArrowCursor));
diff --git a/muse2/muse/audiotrack.cpp b/muse2/muse/audiotrack.cpp
index b9e245d2..f9c298a6 100644
--- a/muse2/muse/audiotrack.cpp
+++ b/muse2/muse/audiotrack.cpp
@@ -1710,9 +1710,32 @@ void AudioAux::write(int level, Xml& xml) const
{
xml.tag(level++, "AudioAux");
AudioTrack::writeProperties(level, xml);
+ xml.intTag(level, "index", _index);
xml.etag(level, "AudioAux");
}
+
+//---------------------------------------------------------
+// getNextAuxIndex
+//---------------------------------------------------------
+int getNextAuxIndex()
+{
+ printf("getNextAuxIndex!\n");
+ int curAux=0;
+ AuxList * al = MusEGlobal::song->auxs();
+ for (MusECore::iAudioAux i = al->begin(); i != al->end(); ++i)
+ {
+ MusECore::AudioAux* ax = *i;
+ printf("ax index %d\n", ax->index());
+ if (ax->index() > curAux)
+ {
+ printf("found new index! %d\n", ax->index());
+ curAux = ax->index();
+ }
+ }
+ return curAux+1;
+}
+
//---------------------------------------------------------
// AudioAux
//---------------------------------------------------------
@@ -1720,25 +1743,27 @@ void AudioAux::write(int level, Xml& xml) const
AudioAux::AudioAux()
: AudioTrack(AUDIO_AUX)
{
+ _index = getNextAuxIndex();
for(int i = 0; i < MAX_CHANNELS; ++i)
{
if(i < channels())
posix_memalign((void**)(buffer + i), 16, sizeof(float) * MusEGlobal::segmentSize);
else
buffer[i] = 0;
- }
+ }
}
AudioAux::AudioAux(const AudioAux& t, int flags)
: AudioTrack(t, flags)
{
+ _index = getNextAuxIndex();
for(int i = 0; i < MAX_CHANNELS; ++i)
{
if(i < channels())
posix_memalign((void**)(buffer + i), 16, sizeof(float) * MusEGlobal::segmentSize);
else
buffer[i] = 0;
- }
+ }
}
//---------------------------------------------------------
// AudioAux
@@ -1766,7 +1791,9 @@ void AudioAux::read(Xml& xml)
case Xml::End:
return;
case Xml::TagStart:
- if (AudioTrack::readProperties(xml, tag))
+ if (tag == "index")
+ _index = xml.parseInt();
+ else if (AudioTrack::readProperties(xml, tag))
xml.unknown("AudioAux");
break;
case Xml::Attribut:
@@ -1839,6 +1866,15 @@ void AudioAux::setChannels(int n)
}
//---------------------------------------------------------
+// setName
+//---------------------------------------------------------
+
+QString AudioAux::auxName()
+{
+ return QString("%1:").arg(index())+ name();
+}
+
+//---------------------------------------------------------
// setRecordFlag1
// gui part (executed in gui thread)
//---------------------------------------------------------
diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp
index da5826e5..fa53f5d4 100644
--- a/muse2/muse/functions.cpp
+++ b/muse2/muse/functions.cpp
@@ -950,20 +950,51 @@ void paste_notes(int max_distance, bool always_new_part, bool never_new_part, Pa
paste_at(s, MusEGlobal::song->cpos(), max_distance, always_new_part, never_new_part, paste_into_part, amount, raster);
}
-
// if nothing is selected/relevant, this function returns NULL
QMimeData* selected_events_to_mime(const set<Part*>& parts, int range)
{
- unsigned start_tick = INT_MAX; //will be the tick of the first event or INT_MAX if no events are there
-
- for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
- for (iEvent ev=(*part)->events()->begin(); ev!=(*part)->events()->end(); ev++)
- if (is_relevant(ev->second, *part, range))
- if (ev->second.tick() < start_tick)
- start_tick=ev->second.tick();
-
- if (start_tick == INT_MAX)
- return NULL;
+ unsigned start_tick = INT_MAX; //will be the tick of the first event or INT_MAX if no events are there
+
+ for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
+ for (iEvent ev=(*part)->events()->begin(); ev!=(*part)->events()->end(); ev++)
+ if (is_relevant(ev->second, *part, range))
+ if (ev->second.tick() < start_tick)
+ start_tick=ev->second.tick();
+
+ if (start_tick == INT_MAX)
+ return NULL;
+
+ //---------------------------------------------------
+ // write events as XML into tmp file
+ //---------------------------------------------------
+
+ FILE* tmp = tmpfile();
+ if (tmp == 0)
+ {
+ fprintf(stderr, "EventCanvas::getTextDrag() fopen failed: %s\n", strerror(errno));
+ return 0;
+ }
+
+ Xml xml(tmp);
+ int level = 0;
+
+ for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
+ {
+ xml.tag(level++, "eventlist part_id=\"%d\"", (*part)->sn());
+ for (iEvent ev=(*part)->events()->begin(); ev!=(*part)->events()->end(); ev++)
+ if (is_relevant(ev->second, *part, range))
+ ev->second.write(level, xml, -start_tick);
+ xml.etag(--level, "eventlist");
+ }
+
+ QMimeData *mimeData = file_to_mimedata(tmp, "text/x-muse-groupedeventlists" );
+ fclose(tmp);
+ return mimeData;
+}
+
+// if nothing is selected/relevant, this function returns NULL
+QMimeData* parts_to_mime(const set<Part*>& parts)
+{
//---------------------------------------------------
// write events as XML into tmp file
@@ -979,40 +1010,52 @@ QMimeData* selected_events_to_mime(const set<Part*>& parts, int range)
Xml xml(tmp);
int level = 0;
+ bool midi=false;
+ bool wave=false;
for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
{
- xml.tag(level++, "eventlist part_id=\"%d\"", (*part)->sn());
- for (iEvent ev=(*part)->events()->begin(); ev!=(*part)->events()->end(); ev++)
- if (is_relevant(ev->second, *part, range))
- ev->second.write(level, xml, -start_tick);
- xml.etag(--level, "eventlist");
- }
+ if ((*part)->track()->type() == MusECore::Track::MIDI)
+ midi=true;
+ else
+ wave=true;
+ (*part)->write(level, xml, true, true);
+ }
+ QString mimeString = "text/x-muse-mixedpartlist";
+ if (!midi)
+ mimeString = "text/x-muse-wavepartlist";
+ else if (!wave)
+ mimeString = "text/x-muse-midipartlist";
+ QMimeData *mimeData = file_to_mimedata(tmp, mimeString );
+ fclose(tmp);
+ return mimeData;
+}
- //---------------------------------------------------
- // read tmp file into drag Object
- //---------------------------------------------------
+//---------------------------------------------------
+// read datafile into mime Object
+//---------------------------------------------------
+QMimeData* file_to_mimedata(FILE *datafile, QString mimeType)
+{
- fflush(tmp);
+ fflush(datafile);
struct stat f_stat;
- if (fstat(fileno(tmp), &f_stat) == -1)
+ if (fstat(fileno(datafile), &f_stat) == -1)
{
fprintf(stderr, "copy_notes() fstat failed:<%s>\n",
strerror(errno));
- fclose(tmp);
+ fclose(datafile);
return 0;
}
int n = f_stat.st_size;
char* fbuf = (char*)mmap(0, n+1, PROT_READ|PROT_WRITE,
- MAP_PRIVATE, fileno(tmp), 0);
+ MAP_PRIVATE, fileno(datafile), 0);
fbuf[n] = 0;
QByteArray data(fbuf);
- QMimeData* md = new QMimeData();
- md->setData("text/x-muse-groupedeventlists", data);
+ QMimeData* md = new QMimeData();
+ md->setData(mimeType, data);
munmap(fbuf, n);
- fclose(tmp);
return md;
}
diff --git a/muse2/muse/functions.h b/muse2/muse/functions.h
index c81dd2bc..31c91fe4 100644
--- a/muse2/muse/functions.h
+++ b/muse2/muse/functions.h
@@ -88,6 +88,9 @@ void copy_notes(const std::set<Part*>& parts, int range);
bool paste_notes(Part* paste_into_part=NULL); // shows a dialog
void paste_notes(int max_distance=3072, bool always_new_part=false, bool never_new_part=false, Part* paste_into_part=NULL, int amount=1, int raster=3072);
QMimeData* selected_events_to_mime(const std::set<Part*>& parts, int range);
+QMimeData* parts_to_mime(const std::set<Part*>& parts);
+
+
void paste_at(const QString& pt, int pos, int max_distance=3072, bool always_new_part=false, bool never_new_part=false, Part* paste_into_part=NULL, int amount=1, int raster=3072);
//functions for selections
@@ -105,6 +108,9 @@ void clean_parts();
bool merge_selected_parts();
bool merge_parts(const std::set<Part*>& parts);
+// internal
+QMimeData* file_to_mimedata(FILE *datafile, QString mimeType);
+
} // namespace MusECore
#endif
diff --git a/muse2/muse/mixer/astrip.cpp b/muse2/muse/mixer/astrip.cpp
index a75968a1..530ca7e2 100644
--- a/muse2/muse/mixer/astrip.cpp
+++ b/muse2/muse/mixer/astrip.cpp
@@ -821,7 +821,11 @@ AudioStrip::AudioStrip(QWidget* parent, MusECore::AudioTrack* at)
for (int idx = 0; idx < auxsSize; ++idx) {
MusEGui::DoubleLabel* al; // the thought was to aquire the correct Aux name for each Aux
// now they are only called Aux1, Aux2, which isn't too usable.
- QLabel *name = new QLabel(((MusECore::Track*)(MusEGlobal::song->auxs()->at(idx)))->name(),this);
+ QString title = ((MusECore::AudioAux*)(MusEGlobal::song->auxs()->at(idx)))->auxName();
+ if (title.length() > 8) { // shorten name
+ title = title.mid(0,8) + ".";
+ }
+ QLabel *name = new QLabel(title,this);
MusEGui::Knob* ak = addKnob(1, idx, &al, name);
auxKnob.push_back(ak);
diff --git a/muse2/muse/mixer/strip.cpp b/muse2/muse/mixer/strip.cpp
index f34d5320..06ee9443 100644
--- a/muse2/muse/mixer/strip.cpp
+++ b/muse2/muse/mixer/strip.cpp
@@ -159,7 +159,11 @@ void Strip::setLabelText()
return;
}
- label->setText(track->name());
+ if (track->type() == MusECore::Track::AUDIO_AUX) {
+ label->setText(((MusECore::AudioAux*)track)->auxName());
+ } else {
+ label->setText(track->name());
+ }
QPalette palette;
//palette.setColor(label->backgroundRole(), c);
QLinearGradient gradient(label->geometry().topLeft(), label->geometry().bottomLeft());
diff --git a/muse2/muse/song.h b/muse2/muse/song.h
index 9a314533..e9e893f1 100644
--- a/muse2/muse/song.h
+++ b/muse2/muse/song.h
@@ -99,6 +99,7 @@ class AudioDevice;
#define SC_MIDI_TRACK_PROP 0x10000000 // a midi track's properties changed (channel, compression etc)
#define SC_SONG_TYPE 0x20000000 // the midi song type (mtype) changed
#define SC_KEY 0x40000000 // key map changed
+#define SC_EVERYTHING -1 // global update
#define REC_NOTE_FIFO_SIZE 16
diff --git a/muse2/muse/track.h b/muse2/muse/track.h
index 3efc6912..c7423ed2 100644
--- a/muse2/muse/track.h
+++ b/muse2/muse/track.h
@@ -560,6 +560,7 @@ class AudioGroup : public AudioTrack {
class AudioAux : public AudioTrack {
float* buffer[MAX_CHANNELS];
static bool _isVisible;
+ int _index;
public:
AudioAux();
AudioAux(const AudioAux& t, int flags);
@@ -575,6 +576,8 @@ class AudioAux : public AudioTrack {
static void setVisible(bool t) { _isVisible = t; }
virtual int height() const;
static bool visible() { return _isVisible; }
+ virtual QString auxName();
+ virtual int index() { return _index; }
};
diff --git a/muse2/muse/waveedit/wavecanvas.cpp b/muse2/muse/waveedit/wavecanvas.cpp
index 8c1b0012..1fa070ec 100644
--- a/muse2/muse/waveedit/wavecanvas.cpp
+++ b/muse2/muse/waveedit/wavecanvas.cpp
@@ -48,6 +48,7 @@
#include <math.h>
#include <errno.h>
#include <sys/wait.h>
+#include <set>
#include "app.h"
#include "xml.h"
@@ -1862,8 +1863,46 @@ void WaveCanvas::cmd(int cmd)
paramA = 0.25;
break;
-
-
+ case CMD_CREATE_PART_REGION:
+ {
+ // create a new part and put in the copy buffer
+ MusECore::Part* pt = editor->curCanvasPart();
+ if (pt == 0 || pt->track()->type() != MusECore::Track::WAVE)
+ return;
+ MusECore::WavePart *origPart = (MusECore::WavePart*)pt;
+ if (MusEGlobal::song->lpos() < origPart->tick() || MusEGlobal::song->rpos() > origPart->endTick())
+ {
+ QMessageBox::warning(this, tr("Part creation failed"),
+ tr("Left and right position markers must be placed inside the current part."),
+ QMessageBox::Ok, QMessageBox::Ok);
+ return;
+ }
+ MusECore::WavePart *tempPart = new MusECore::WavePart(origPart->track());
+ unsigned origFrame = origPart->frame();
+ unsigned frameDistance = MusEGlobal::song->lPos().frame() - origFrame;
+ tempPart->setPos(MusEGlobal::song->lpos());
+ tempPart->setLenTick(MusEGlobal::song->rpos() - MusEGlobal::song->lpos());
+ // loop through the events and set them accordingly
+ for (MusECore::iEvent iWaveEvent = origPart->events()->begin(); iWaveEvent != origPart->events()->end(); iWaveEvent++)
+ {
+ // TODO: handle multiple events correctly,
+ // the math for subsequent events isn't correct
+ MusECore::Event &ev = iWaveEvent->second;
+ MusECore::Event *newEvent = new MusECore::Event(ev.clone());
+ newEvent->setSpos(ev.spos() + frameDistance);
+ newEvent->setLenTick(MusEGlobal::song->rpos() - MusEGlobal::song->lpos());
+ tempPart->addEvent(*newEvent);
+ }
+ std::set<MusECore::Part*> partList;
+ partList.insert(tempPart);
+
+ QMimeData *mimeData = MusECore::parts_to_mime(partList);
+ QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
+ QMessageBox::information(this, tr("Part created"),
+ tr("The selected region has been copied to the clipboard and can be pasted in the arranger."),
+ QMessageBox::Ok, QMessageBox::Ok);
+ }
+ break;
case CMD_ERASE_MEASURE:
case CMD_DELETE_MEASURE:
case CMD_CREATE_MEASURE:
diff --git a/muse2/muse/waveedit/wavecanvas.h b/muse2/muse/waveedit/wavecanvas.h
index f9553845..5ad836bc 100644
--- a/muse2/muse/waveedit/wavecanvas.h
+++ b/muse2/muse/waveedit/wavecanvas.h
@@ -154,6 +154,7 @@ class WaveCanvas : public EventCanvas {
enum { CMD_MUTE=0, CMD_NORMALIZE, CMD_FADE_IN, CMD_FADE_OUT, CMD_REVERSE,
CMD_GAIN_FREE, CMD_GAIN_200, CMD_GAIN_150, CMD_GAIN_75, CMD_GAIN_50, CMD_GAIN_25,
CMD_EDIT_COPY, CMD_EDIT_CUT, CMD_EDIT_PASTE, CMD_PASTE_DIALOG, CMD_DEL,
+ CMD_CREATE_PART_REGION,
CMD_EDIT_EXTERNAL,
CMD_QUANTIZE,
CMD_SELECT_ALL, CMD_SELECT_NONE, CMD_SELECT_INVERT,
diff --git a/muse2/muse/waveedit/waveedit.cpp b/muse2/muse/waveedit/waveedit.cpp
index 56185a83..ca98e380 100644
--- a/muse2/muse/waveedit/waveedit.cpp
+++ b/muse2/muse/waveedit/waveedit.cpp
@@ -139,6 +139,10 @@ WaveEdit::WaveEdit(MusECore::PartList* pl)
mapper->setMapping(copyAction, WaveCanvas::CMD_EDIT_COPY);
connect(copyAction, SIGNAL(triggered()), mapper, SLOT(map()));
+ copyPartRegionAction = menuEdit->addAction(tr("&Create Part from Region"));
+ mapper->setMapping(copyPartRegionAction, WaveCanvas::CMD_CREATE_PART_REGION);
+ connect(copyPartRegionAction, SIGNAL(triggered()), mapper, SLOT(map()));
+
cutAction = menuEdit->addAction(tr("C&ut"));
mapper->setMapping(cutAction, WaveCanvas::CMD_EDIT_CUT);
connect(cutAction, SIGNAL(triggered()), mapper, SLOT(map()));
diff --git a/muse2/muse/waveedit/waveedit.h b/muse2/muse/waveedit/waveedit.h
index 7165a63a..f0bcf199 100644
--- a/muse2/muse/waveedit/waveedit.h
+++ b/muse2/muse/waveedit/waveedit.h
@@ -68,6 +68,7 @@ class WaveEdit : public MidiEditor {
QAction* selectNoneAction;
QAction* cutAction;
QAction* copyAction;
+ QAction* copyPartRegionAction;
QAction* pasteAction;
QAction* selectPrevPartAction;
QAction* selectNextPartAction;