Merge pull request #4655 from dmitrio95/parts-playback
fix #109941: Single parts playback
This commit is contained in:
commit
27dc9000ca
26 changed files with 589 additions and 368 deletions
|
@ -25,6 +25,7 @@
|
|||
namespace Ms {
|
||||
|
||||
Instrument InstrumentList::defaultInstrument;
|
||||
constexpr std::initializer_list<Channel::Prop> PartChannelSettingsLink::excerptProperties;
|
||||
|
||||
//---------------------------------------------------------
|
||||
// write
|
||||
|
@ -197,7 +198,7 @@ void StaffName::read(XmlReader& e)
|
|||
// Instrument::write
|
||||
//---------------------------------------------------------
|
||||
|
||||
void Instrument::write(XmlWriter& xml, Part* part) const
|
||||
void Instrument::write(XmlWriter& xml, const Part* part) const
|
||||
{
|
||||
xml.stag("Instrument");
|
||||
_longNames.write(xml, "longName");
|
||||
|
@ -600,7 +601,7 @@ void Channel::setSolo(bool value)
|
|||
// write
|
||||
//---------------------------------------------------------
|
||||
|
||||
void Channel::write(XmlWriter& xml, Part* part) const
|
||||
void Channel::write(XmlWriter& xml, const Part* part) const
|
||||
{
|
||||
if (_name.isEmpty() || _name == DEFAULT_NAME)
|
||||
xml.stag("Channel");
|
||||
|
@ -640,8 +641,8 @@ void Channel::write(XmlWriter& xml, Part* part) const
|
|||
if (_solo)
|
||||
xml.tag("solo", _solo);
|
||||
if (part && part->masterScore()->exportMidiMapping() && part->score() == part->masterScore()) {
|
||||
xml.tag("midiPort", part->masterScore()->midiMapping(_channel)->port);
|
||||
xml.tag("midiChannel", part->masterScore()->midiMapping(_channel)->channel);
|
||||
xml.tag("midiPort", part->masterScore()->midiMapping(_channel)->port());
|
||||
xml.tag("midiChannel", part->masterScore()->midiMapping(_channel)->channel());
|
||||
}
|
||||
for (const NamedEventList& a : midiActions)
|
||||
a.write(xml, "MidiAction");
|
||||
|
@ -727,20 +728,13 @@ void Channel::read(XmlReader& e, Part* part)
|
|||
_solo = e.readInt();
|
||||
else if (tag == "midiPort") {
|
||||
int midiPort = e.readInt();
|
||||
if (part) {
|
||||
MidiMapping mm;
|
||||
mm.port = midiPort;
|
||||
mm.channel = -1;
|
||||
mm.part = part;
|
||||
mm.articulation = this;
|
||||
part->masterScore()->midiMapping()->append(mm);
|
||||
_channel = part->masterScore()->midiMapping()->size() - 1;
|
||||
}
|
||||
if (part && part->score()->isMaster())
|
||||
part->masterScore()->addMidiMapping(this, part, midiPort, -1);
|
||||
}
|
||||
else if (tag == "midiChannel") {
|
||||
int midiChannel = e.readInt();
|
||||
if (part)
|
||||
part->masterScore()->midiMapping(_channel)->channel = midiChannel;
|
||||
if (part && part->score()->isMaster())
|
||||
part->masterScore()->updateMidiMapping(this, part, -1, midiChannel);
|
||||
}
|
||||
else
|
||||
e.unknown();
|
||||
|
@ -802,6 +796,138 @@ void Channel::removeListener(ChannelListener* l)
|
|||
_notifier.removeListener(l);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// PartChannelSettingsLink
|
||||
//---------------------------------------------------------
|
||||
|
||||
PartChannelSettingsLink::PartChannelSettingsLink(Channel* main, Channel* bound, bool excerpt)
|
||||
: _main(main), _bound(bound), _excerpt(excerpt)
|
||||
{
|
||||
if (excerpt) {
|
||||
for (Channel::Prop p : excerptProperties)
|
||||
applyProperty(p, /* from */ bound, /* to */ main);
|
||||
}
|
||||
// Maybe it would be good to assign common properties if the link
|
||||
// is constructed in non-excerpt mode. But it is not currently
|
||||
// necessary as playback channels are currently recreated on each
|
||||
// MIDI remapping.
|
||||
|
||||
main->addListener(this);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// PartChannelSettingsLink
|
||||
//---------------------------------------------------------
|
||||
|
||||
PartChannelSettingsLink::PartChannelSettingsLink(PartChannelSettingsLink&& other)
|
||||
: _main(nullptr), _bound(nullptr), _excerpt(false)
|
||||
{
|
||||
swap(*this, other);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// PartChannelSettingsLink::operator=
|
||||
//---------------------------------------------------------
|
||||
|
||||
PartChannelSettingsLink& PartChannelSettingsLink::operator=(PartChannelSettingsLink&& other)
|
||||
{
|
||||
if (this != &other)
|
||||
swap(*this, other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// ~PartChannelSettingsLink
|
||||
//---------------------------------------------------------
|
||||
|
||||
PartChannelSettingsLink::~PartChannelSettingsLink()
|
||||
{
|
||||
if (_main)
|
||||
_main->removeListener(this);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// swap
|
||||
//---------------------------------------------------------
|
||||
|
||||
void swap(PartChannelSettingsLink& l1, PartChannelSettingsLink& l2)
|
||||
{
|
||||
using std::swap;
|
||||
if (l1._main)
|
||||
l1._main->removeListener(&l1);
|
||||
if (l2._main)
|
||||
l2._main->removeListener(&l2);
|
||||
swap(l1._main, l2._main);
|
||||
swap(l1._bound, l2._bound);
|
||||
swap(l1._excerpt, l2._excerpt);
|
||||
if (l1._main)
|
||||
l1._main->addListener(&l1);
|
||||
if (l2._main)
|
||||
l2._main->addListener(&l2);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// PartChannelSettingsLink::applyProperty
|
||||
//---------------------------------------------------------
|
||||
|
||||
void PartChannelSettingsLink::applyProperty(Channel::Prop p, const Channel* from, Channel* to)
|
||||
{
|
||||
switch (p) {
|
||||
case Channel::Prop::VOLUME:
|
||||
to->setVolume(from->volume());
|
||||
break;
|
||||
case Channel::Prop::PAN:
|
||||
to->setPan(from->pan());
|
||||
break;
|
||||
case Channel::Prop::CHORUS:
|
||||
to->setChorus(from->chorus());
|
||||
break;
|
||||
case Channel::Prop::REVERB:
|
||||
to->setReverb(from->reverb());
|
||||
break;
|
||||
case Channel::Prop::NAME:
|
||||
to->setName(from->name());
|
||||
break;
|
||||
case Channel::Prop::DESCR:
|
||||
to->setDescr(from->descr());
|
||||
break;
|
||||
case Channel::Prop::PROGRAM:
|
||||
to->setProgram(from->program());
|
||||
break;
|
||||
case Channel::Prop::BANK:
|
||||
to->setBank(from->bank());
|
||||
break;
|
||||
case Channel::Prop::COLOR:
|
||||
to->setColor(from->color());
|
||||
break;
|
||||
case Channel::Prop::SOLOMUTE:
|
||||
to->setSoloMute(from->soloMute());
|
||||
break;
|
||||
case Channel::Prop::SOLO:
|
||||
to->setSolo(from->solo());
|
||||
break;
|
||||
case Channel::Prop::MUTE:
|
||||
to->setMute(from->mute());
|
||||
break;
|
||||
case Channel::Prop::SYNTI:
|
||||
to->setSynti(from->synti());
|
||||
break;
|
||||
case Channel::Prop::CHANNEL:
|
||||
to->setChannel(from->channel());
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// PartChannelSettingsLink::propertyChanged
|
||||
//---------------------------------------------------------
|
||||
|
||||
void PartChannelSettingsLink::propertyChanged(Channel::Prop p)
|
||||
{
|
||||
if (isExcerptProperty(p) == _excerpt)
|
||||
applyProperty(p, _main, _bound);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// channelIdx
|
||||
//---------------------------------------------------------
|
||||
|
@ -1202,6 +1328,25 @@ Instrument Instrument::fromTemplate(const InstrumentTemplate* t)
|
|||
return instr;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Instrument::playbackChannel
|
||||
//---------------------------------------------------------
|
||||
|
||||
const Channel* Instrument::playbackChannel(int idx, const MasterScore* score) const
|
||||
{
|
||||
return score->playbackChannel(channel(idx));
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Instrument::playbackChannel
|
||||
//---------------------------------------------------------
|
||||
|
||||
Channel* Instrument::playbackChannel(int idx, MasterScore* score)
|
||||
{
|
||||
return score->playbackChannel(channel(idx));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// StaffNameList::write
|
||||
//---------------------------------------------------------
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
namespace Ms {
|
||||
|
||||
class InstrumentTemplate;
|
||||
class MasterScore;
|
||||
class XmlWriter;
|
||||
class XmlReader;
|
||||
class Drumset;
|
||||
|
@ -141,7 +142,6 @@ public:
|
|||
|
||||
mutable std::vector<MidiCoreEvent> init;
|
||||
|
||||
|
||||
QString name() const { return _name; }
|
||||
void setName(const QString& value);
|
||||
QString descr() const { return _descr; }
|
||||
|
@ -178,7 +178,7 @@ public:
|
|||
QList<MidiArticulation> articulation;
|
||||
|
||||
Channel();
|
||||
void write(XmlWriter&, Part *part) const;
|
||||
void write(XmlWriter&, const Part* part) const;
|
||||
void read(XmlReader&, Part *part);
|
||||
void updateInitList() const;
|
||||
bool operator==(const Channel& c) { return (_name == c._name) && (_channel == c._channel); }
|
||||
|
@ -200,6 +200,39 @@ class ChannelListener : public Listener<Channel::Prop> {
|
|||
void receive(Channel::Prop prop) override { propertyChanged(prop); }
|
||||
};
|
||||
|
||||
//---------------------------------------------------------
|
||||
// PartChannelSettingsLink
|
||||
//---------------------------------------------------------
|
||||
|
||||
class PartChannelSettingsLink final : private ChannelListener {
|
||||
// A list of properties which may vary for different excerpts.
|
||||
static constexpr std::initializer_list<Channel::Prop> excerptProperties {
|
||||
Channel::Prop::SOLOMUTE,
|
||||
Channel::Prop::SOLO,
|
||||
Channel::Prop::MUTE,
|
||||
};
|
||||
|
||||
private:
|
||||
Channel* _main;
|
||||
Channel* _bound;
|
||||
bool _excerpt;
|
||||
|
||||
static bool isExcerptProperty(Channel::Prop p) { return std::find(excerptProperties.begin(), excerptProperties.end(), p) != excerptProperties.end(); }
|
||||
static void applyProperty(Channel::Prop p, const Channel* from, Channel* to);
|
||||
void propertyChanged(Channel::Prop p) override;
|
||||
|
||||
public:
|
||||
PartChannelSettingsLink() : _main(nullptr), _bound(nullptr), _excerpt(false) {}
|
||||
PartChannelSettingsLink(Channel* main, Channel* bound, bool excerpt);
|
||||
PartChannelSettingsLink(const PartChannelSettingsLink&) = delete;
|
||||
PartChannelSettingsLink(PartChannelSettingsLink&&);
|
||||
PartChannelSettingsLink& operator=(const PartChannelSettingsLink&) = delete;
|
||||
PartChannelSettingsLink& operator=(PartChannelSettingsLink&&);
|
||||
~PartChannelSettingsLink();
|
||||
|
||||
friend void swap(PartChannelSettingsLink&, PartChannelSettingsLink&);
|
||||
};
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Instrument
|
||||
//---------------------------------------------------------
|
||||
|
@ -230,7 +263,7 @@ class Instrument {
|
|||
|
||||
void read(XmlReader&, Part *part);
|
||||
bool readProperties(XmlReader&, Part* , bool* customDrumset);
|
||||
void write(XmlWriter& xml, Part *part) const;
|
||||
void write(XmlWriter& xml, const Part* part) const;
|
||||
NamedEventList* midiAction(const QString& s, int channel) const;
|
||||
int channelIdx(const QString& s) const;
|
||||
void updateVelocity(int* velocity, int channel, const QString& name);
|
||||
|
@ -256,6 +289,8 @@ class Instrument {
|
|||
void setProfessionalPitchRange(int a, int b) { _minPitchP = a; _maxPitchP = b; }
|
||||
Channel* channel(int idx) { return _channel[idx]; }
|
||||
const Channel* channel(int idx) const { return _channel[idx]; }
|
||||
Channel* playbackChannel(int idx, MasterScore*);
|
||||
const Channel* playbackChannel(int idx, const MasterScore*) const;
|
||||
ClefTypeList clefType(int staffIdx) const;
|
||||
void setClefType(int staffIdx, const ClefTypeList& c);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
|
||||
#include "score.h"
|
||||
#include "excerpt.h"
|
||||
#include "instrument.h"
|
||||
#include "part.h"
|
||||
|
||||
|
@ -23,10 +24,16 @@ namespace Ms {
|
|||
|
||||
void MasterScore::rebuildMidiMapping()
|
||||
{
|
||||
Score* playbackScore = _playbackScore ? _playbackScore : this;
|
||||
setPlaybackScore(nullptr);
|
||||
|
||||
removeDeletedMidiMapping();
|
||||
int maxport = updateMidiMapping();
|
||||
reorderMidiMapping();
|
||||
rebuildExcerptsMidiMapping();
|
||||
masterScore()->setMidiPortCount(maxport);
|
||||
|
||||
setPlaybackScore(playbackScore);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
@ -53,12 +60,12 @@ void MasterScore::checkMidiMapping()
|
|||
int lastChannel = -1; // port*16+channel
|
||||
int lastDrumPort = -1;
|
||||
int index = 0;
|
||||
for (MidiMapping m : _midiMapping) {
|
||||
for (const MidiMapping& m : _midiMapping) {
|
||||
if (index >= drum.size())
|
||||
break;
|
||||
if (drum[index]) {
|
||||
lastDrumPort++;
|
||||
if (m.port != lastDrumPort) {
|
||||
if (m.port() != lastDrumPort) {
|
||||
isSimpleMidiMaping = false;
|
||||
return;
|
||||
}
|
||||
|
@ -69,7 +76,7 @@ void MasterScore::checkMidiMapping()
|
|||
lastChannel++;
|
||||
int p = lastChannel / 16;
|
||||
int c = lastChannel % 16;
|
||||
if (m.port != p || m.channel != c) {
|
||||
if (m.port() != p || m.channel() != c) {
|
||||
isSimpleMidiMaping = false;
|
||||
return;
|
||||
}
|
||||
|
@ -126,6 +133,36 @@ int MasterScore::getNextFreeDrumMidiMapping()
|
|||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// rebuildExcerptsMidiMapping
|
||||
//---------------------------------------------------------
|
||||
|
||||
void MasterScore::rebuildExcerptsMidiMapping()
|
||||
{
|
||||
for (Excerpt* ex : excerpts()) {
|
||||
for (Part* p : ex->partScore()->parts()) {
|
||||
const Part* masterPart = p->masterPart();
|
||||
if (!masterPart->score()->isMaster()) {
|
||||
qWarning("reorderMidiMapping: no part in master score is linked");
|
||||
continue;
|
||||
}
|
||||
Q_ASSERT(p->instruments()->size() == masterPart->instruments()->size());
|
||||
for (const auto& item : *masterPart->instruments()) {
|
||||
const Instrument* iMaster = item.second;
|
||||
const int tick = item.first;
|
||||
Instrument* iLocal = p->instrument(tick);
|
||||
Q_ASSERT(iLocal->channel().size() == iMaster->channel().size());
|
||||
const int nchannels = iLocal->channel().size();
|
||||
for (int c = 0; c < nchannels; ++c) {
|
||||
Channel* cLocal = iLocal->channel(c);
|
||||
const Channel* cMaster = iMaster->channel(c);
|
||||
cLocal->setChannel(cMaster->channel());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// reorderMidiMapping
|
||||
// Set mappings in order you see in Add->Instruments
|
||||
|
@ -133,19 +170,20 @@ int MasterScore::getNextFreeDrumMidiMapping()
|
|||
|
||||
void MasterScore::reorderMidiMapping()
|
||||
{
|
||||
using std::swap;
|
||||
int sequenceNumber = 0;
|
||||
for (Part* part : parts()) {
|
||||
const InstrumentList* il = part->instruments();
|
||||
for (auto i = il->begin(); i != il->end(); ++i) {
|
||||
const Instrument* instr = i->second;
|
||||
for (Channel* channel : instr->channel()) {
|
||||
if (!(_midiMapping[sequenceNumber].part == part
|
||||
&& _midiMapping[sequenceNumber].articulation == channel)) {
|
||||
if (!(_midiMapping[sequenceNumber].part() == part
|
||||
&& _midiMapping[sequenceNumber].masterChannel == channel)) {
|
||||
int shouldBe = channel->channel();
|
||||
_midiMapping.swap(sequenceNumber, shouldBe);
|
||||
_midiMapping[sequenceNumber].articulation->setChannel(sequenceNumber);
|
||||
swap(_midiMapping[sequenceNumber], _midiMapping[shouldBe]);
|
||||
_midiMapping[sequenceNumber].articulation()->setChannel(sequenceNumber);
|
||||
channel->setChannel(sequenceNumber);
|
||||
_midiMapping[shouldBe].articulation->setChannel(shouldBe);
|
||||
_midiMapping[shouldBe].articulation()->setChannel(shouldBe);
|
||||
}
|
||||
sequenceNumber++;
|
||||
}
|
||||
|
@ -163,7 +201,7 @@ void MasterScore::removeDeletedMidiMapping()
|
|||
int removeOffset = 0;
|
||||
int mappingSize = _midiMapping.size();
|
||||
for (int index = 0; index < mappingSize; index++) {
|
||||
Part* p = midiMapping(index)->part;
|
||||
Part* p = midiMapping(index)->part();
|
||||
if (!parts().contains(p)) {
|
||||
removeOffset++;
|
||||
continue;
|
||||
|
@ -173,9 +211,9 @@ void MasterScore::removeDeletedMidiMapping()
|
|||
const InstrumentList* il = p->instruments();
|
||||
for (auto i = il->begin(); i != il->end() && !channelExists; ++i) {
|
||||
const Instrument* instr = i->second;
|
||||
channelExists = (_midiMapping[index].articulation->channel() != -1
|
||||
&& instr->channel().contains(_midiMapping[index].articulation)
|
||||
&& !(_midiMapping[index].port == -1 && _midiMapping[index].channel == -1));
|
||||
channelExists = (_midiMapping[index].articulation()->channel() != -1
|
||||
&& instr->channel().contains(_midiMapping[index].masterChannel)
|
||||
&& !(_midiMapping[index].port() == -1 && _midiMapping[index].channel() == -1));
|
||||
if (channelExists)
|
||||
break;
|
||||
}
|
||||
|
@ -185,15 +223,15 @@ void MasterScore::removeDeletedMidiMapping()
|
|||
}
|
||||
// Let's do a left shift by 'removeOffset' items if necessary
|
||||
if (index != 0 && removeOffset != 0) {
|
||||
_midiMapping[index-removeOffset] = _midiMapping[index];
|
||||
_midiMapping[index-removeOffset] = std::move(_midiMapping[index]);
|
||||
|
||||
int chanVal = _midiMapping[index-removeOffset].articulation->channel();
|
||||
_midiMapping[index-removeOffset].articulation->setChannel(chanVal - removeOffset);
|
||||
const int chanVal = _midiMapping[index-removeOffset].articulation()->channel();
|
||||
_midiMapping[index-removeOffset].articulation()->setChannel(chanVal - removeOffset);
|
||||
}
|
||||
}
|
||||
// We have 'removeOffset' deleted instruments, let's remove their mappings
|
||||
for (int index = 0; index < removeOffset; index++)
|
||||
_midiMapping.removeLast();
|
||||
_midiMapping.pop_back();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
@ -208,12 +246,12 @@ int MasterScore::updateMidiMapping()
|
|||
searchMidiMappingFrom = 0;
|
||||
occupiedMidiChannels.reserve(_midiMapping.size()); // Bringing down the complexity of insertion to amortized O(1)
|
||||
|
||||
for(MidiMapping mm :_midiMapping) {
|
||||
if (mm.port == -1 || mm.channel == -1)
|
||||
for (const MidiMapping& mm :_midiMapping) {
|
||||
if (mm.port() == -1 || mm.channel() == -1)
|
||||
continue;
|
||||
occupiedMidiChannels.insert((int)(mm.port)*16+(int)mm.channel);
|
||||
if (maxport < mm.port)
|
||||
maxport = mm.port;
|
||||
occupiedMidiChannels.insert((int)(mm.port())*16+(int)mm.channel());
|
||||
if (maxport < mm.port())
|
||||
maxport = mm.port();
|
||||
}
|
||||
|
||||
for (Part* part : parts()) {
|
||||
|
@ -223,55 +261,100 @@ int MasterScore::updateMidiMapping()
|
|||
bool drum = instr->useDrumset();
|
||||
for (Channel* channel : instr->channel()) {
|
||||
bool channelExists = false;
|
||||
for (MidiMapping mapping: _midiMapping) {
|
||||
if (channel == mapping.articulation && channel->channel() != -1) {
|
||||
for (const MidiMapping& mapping: _midiMapping) {
|
||||
if (channel == mapping.masterChannel && channel->channel() != -1) {
|
||||
channelExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Channel could already exist, but have unassigned port or channel. Repair and continue
|
||||
if (channelExists) {
|
||||
if (_midiMapping[channel->channel()].port == -1) {
|
||||
int nm = getNextFreeMidiMapping(-1, _midiMapping[channel->channel()].channel);
|
||||
_midiMapping[channel->channel()].port = nm / 16;
|
||||
if (_midiMapping[channel->channel()].port() == -1) {
|
||||
const int nm = getNextFreeMidiMapping(-1, _midiMapping[channel->channel()].channel());
|
||||
_midiMapping[channel->channel()]._port = nm / 16;
|
||||
}
|
||||
else if (_midiMapping[channel->channel()].channel == -1) {
|
||||
else if (_midiMapping[channel->channel()].channel() == -1) {
|
||||
if (drum) {
|
||||
_midiMapping[channel->channel()].port = getNextFreeDrumMidiMapping() / 16;
|
||||
_midiMapping[channel->channel()].channel = 9;
|
||||
_midiMapping[channel->channel()]._port = getNextFreeDrumMidiMapping() / 16;
|
||||
_midiMapping[channel->channel()]._channel = 9;
|
||||
continue;
|
||||
}
|
||||
int nm = getNextFreeMidiMapping(_midiMapping[channel->channel()].port);
|
||||
_midiMapping[channel->channel()].port = nm / 16;
|
||||
_midiMapping[channel->channel()].channel = nm % 16;
|
||||
int nm = getNextFreeMidiMapping(_midiMapping[channel->channel()].port());
|
||||
_midiMapping[channel->channel()]._port = nm / 16;
|
||||
_midiMapping[channel->channel()]._channel = nm % 16;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
MidiMapping mm;
|
||||
int midiPort;
|
||||
int midiChannel;
|
||||
if (drum) {
|
||||
mm.port = getNextFreeDrumMidiMapping() / 16;
|
||||
mm.channel = 9;
|
||||
midiPort = getNextFreeDrumMidiMapping() / 16;
|
||||
midiChannel = 9;
|
||||
}
|
||||
else {
|
||||
int nm = getNextFreeMidiMapping();
|
||||
mm.port = nm / 16;
|
||||
mm.channel = nm % 16;
|
||||
midiPort = nm / 16;
|
||||
midiChannel = nm % 16;
|
||||
}
|
||||
|
||||
if (mm.port > maxport)
|
||||
maxport = mm.port;
|
||||
if (midiPort > maxport)
|
||||
maxport = midiPort;
|
||||
|
||||
mm.part = part;
|
||||
mm.articulation = channel;
|
||||
|
||||
_midiMapping.append(mm);
|
||||
channel->setChannel(_midiMapping.size() - 1);
|
||||
addMidiMapping(channel, part, midiPort, midiChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
return maxport;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// addMidiMapping
|
||||
//---------------------------------------------------------
|
||||
|
||||
void MasterScore::addMidiMapping(Channel* channel, Part* part, int midiPort, int midiChannel)
|
||||
{
|
||||
if (!part->score()->isMaster())
|
||||
return;
|
||||
|
||||
MidiMapping mm;
|
||||
mm._part = part;
|
||||
mm.masterChannel = channel;
|
||||
mm._articulation.reset(new Channel(*channel));
|
||||
mm.link = PartChannelSettingsLink(mm.articulation(), mm.masterChannel, /* excerpt */ false);
|
||||
|
||||
mm._port = midiPort;
|
||||
mm._channel = midiChannel;
|
||||
|
||||
const int mscoreChannel = _midiMapping.size();
|
||||
mm._articulation->setChannel(mscoreChannel);
|
||||
mm.masterChannel->setChannel(mscoreChannel);
|
||||
|
||||
_midiMapping.push_back(std::move(mm));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// updateMidiMapping
|
||||
//---------------------------------------------------------
|
||||
|
||||
void MasterScore::updateMidiMapping(Channel* channel, Part* part, int midiPort, int midiChannel)
|
||||
{
|
||||
const int c = channel->channel();
|
||||
if (c < 0)
|
||||
return;
|
||||
if (c >= int(masterScore()->midiMapping().size())) {
|
||||
qDebug("Can't set midi channel: midiMapping is empty!");
|
||||
return;
|
||||
}
|
||||
MidiMapping& mm = _midiMapping[c];
|
||||
|
||||
if (midiChannel != -1)
|
||||
mm._channel = midiChannel;
|
||||
if (midiPort != -1)
|
||||
mm._port = midiPort;
|
||||
if (part)
|
||||
mm._part = part->masterPart();
|
||||
}
|
||||
|
||||
} // namespace Ms
|
||||
|
||||
|
|
|
@ -92,30 +92,6 @@ Part* Part::masterPart()
|
|||
return const_cast<Part*>(const_cast<const Part*>(this)->masterPart());
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Part::redirectPart
|
||||
//---------------------------------------------------------
|
||||
|
||||
const Part* Part::redirectPart() const
|
||||
{
|
||||
const Part* p = masterPart();
|
||||
if (p != this)
|
||||
return p;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Part::redirectPart
|
||||
//---------------------------------------------------------
|
||||
|
||||
Part* Part::redirectPart()
|
||||
{
|
||||
Part* p = masterPart();
|
||||
if (p != this)
|
||||
return p;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// readProperties
|
||||
//---------------------------------------------------------
|
||||
|
@ -178,7 +154,7 @@ void Part::write(XmlWriter& xml) const
|
|||
xml.tag("trackName", _partName);
|
||||
if (_color != DEFAULT_COLOR)
|
||||
xml.tag("color", _color);
|
||||
instrument()->write(xml, const_cast<Part*>(this)); // Safe, we do not write anything to it
|
||||
instrument()->write(xml, this);
|
||||
xml.etag();
|
||||
}
|
||||
|
||||
|
@ -260,103 +236,13 @@ void Part::setMidiProgram(int program, int bank)
|
|||
// instrument()->setChannel(0, c);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// volume
|
||||
//---------------------------------------------------------
|
||||
|
||||
double Part::volume() const
|
||||
{
|
||||
return instrument()->channel(0)->volume();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// setVolume
|
||||
//---------------------------------------------------------
|
||||
|
||||
void Part::setVolume(double volume)
|
||||
{
|
||||
instrument()->channel(0)->setVolume(volume);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// mute
|
||||
//---------------------------------------------------------
|
||||
|
||||
bool Part::mute() const
|
||||
{
|
||||
return instrument()->channel(0)->mute();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// setMute
|
||||
//---------------------------------------------------------
|
||||
|
||||
void Part::setMute(bool mute)
|
||||
{
|
||||
instrument()->channel(0)->setMute(mute);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// reverb
|
||||
//---------------------------------------------------------
|
||||
|
||||
double Part::reverb() const
|
||||
{
|
||||
return instrument()->channel(0)->reverb();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// setReverb
|
||||
//---------------------------------------------------------
|
||||
|
||||
void Part::setReverb(double val)
|
||||
{
|
||||
instrument()->channel(0)->setReverb(val);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// chorus
|
||||
//---------------------------------------------------------
|
||||
|
||||
double Part::chorus() const
|
||||
{
|
||||
return instrument()->channel(0)->chorus();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// setChorus
|
||||
//---------------------------------------------------------
|
||||
|
||||
void Part::setChorus(double val)
|
||||
{
|
||||
instrument()->channel(0)->setChorus(val);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// pan
|
||||
//---------------------------------------------------------
|
||||
|
||||
double Part::pan() const
|
||||
{
|
||||
return instrument()->channel(0)->pan();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// setPan
|
||||
//---------------------------------------------------------
|
||||
|
||||
void Part::setPan(double pan)
|
||||
{
|
||||
instrument()->channel(0)->setPan(pan);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// midiProgram
|
||||
//---------------------------------------------------------
|
||||
|
||||
int Part::midiProgram() const
|
||||
{
|
||||
return instrument()->channel(0)->program();
|
||||
return instrument()->playbackChannel(0, masterScore())->program();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
@ -390,33 +276,10 @@ int Part::midiPort() const
|
|||
void Part::setMidiChannel(int ch, int port, int tick)
|
||||
{
|
||||
Channel* channel = instrument(tick)->channel(0);
|
||||
if (channel->channel() == -1) {
|
||||
// Add new mapping
|
||||
MidiMapping mm;
|
||||
mm.part = this;
|
||||
mm.articulation = channel;
|
||||
mm.channel = -1;
|
||||
mm.port = -1;
|
||||
if (ch != -1)
|
||||
mm.channel = ch;
|
||||
if (port != -1)
|
||||
mm.port = port;
|
||||
channel->setChannel(masterScore()->midiMapping()->size());
|
||||
masterScore()->midiMapping()->append(mm);
|
||||
}
|
||||
else {
|
||||
// Update existing mapping
|
||||
if (channel->channel() >= masterScore()->midiMapping()->size()) {
|
||||
qDebug()<<"Can't' set midi channel: midiMapping is empty!";
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch != -1)
|
||||
masterScore()->midiMapping(channel->channel())->channel = ch;
|
||||
if (port != -1)
|
||||
masterScore()->midiMapping(channel->channel())->port = port;
|
||||
masterScore()->midiMapping(channel->channel())->part = this;
|
||||
}
|
||||
if (channel->channel() == -1)
|
||||
masterScore()->addMidiMapping(channel, this, port, ch);
|
||||
else
|
||||
masterScore()->updateMidiMapping(channel, this, port, ch);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
@ -457,8 +320,6 @@ void Part::removeInstrument(int tick)
|
|||
|
||||
Instrument* Part::instrument(int tick)
|
||||
{
|
||||
if (Part* p = redirectPart())
|
||||
return p->instrument(tick);
|
||||
return _instruments.instrument(tick);
|
||||
}
|
||||
|
||||
|
@ -468,8 +329,6 @@ Instrument* Part::instrument(int tick)
|
|||
|
||||
const Instrument* Part::instrument(int tick) const
|
||||
{
|
||||
if (const Part* p = redirectPart())
|
||||
return p->instrument(tick);
|
||||
return _instruments.instrument(tick);
|
||||
}
|
||||
|
||||
|
@ -479,8 +338,6 @@ const Instrument* Part::instrument(int tick) const
|
|||
|
||||
const InstrumentList* Part::instruments() const
|
||||
{
|
||||
if (const Part* p = redirectPart())
|
||||
return p->instruments();
|
||||
return &_instruments;
|
||||
}
|
||||
|
||||
|
@ -569,16 +426,6 @@ QVariant Part::getProperty(Pid id) const
|
|||
return QVariant(_show);
|
||||
case Pid::USE_DRUMSET:
|
||||
return instrument()->useDrumset();
|
||||
case Pid::PART_VOLUME:
|
||||
return volume();
|
||||
case Pid::PART_MUTE:
|
||||
return mute();
|
||||
case Pid::PART_PAN:
|
||||
return pan();
|
||||
case Pid::PART_REVERB:
|
||||
return reverb();
|
||||
case Pid::PART_CHORUS:
|
||||
return chorus();
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
@ -597,21 +444,6 @@ bool Part::setProperty(Pid id, const QVariant& property)
|
|||
case Pid::USE_DRUMSET:
|
||||
instrument()->setUseDrumset(property.toBool());
|
||||
break;
|
||||
case Pid::PART_VOLUME:
|
||||
setVolume(property.toInt());
|
||||
break;
|
||||
case Pid::PART_MUTE:
|
||||
setMute(property.toBool());
|
||||
break;
|
||||
case Pid::PART_PAN:
|
||||
setPan(property.toInt());
|
||||
break;
|
||||
case Pid::PART_REVERB:
|
||||
setReverb(property.toInt());
|
||||
break;
|
||||
case Pid::PART_CHORUS:
|
||||
setChorus(property.toInt());
|
||||
break;
|
||||
default:
|
||||
qDebug("Part::setProperty: unknown id %d", int(id));
|
||||
break;
|
||||
|
|
|
@ -54,11 +54,6 @@ class Part final : public ScoreElement {
|
|||
static const int DEFAULT_COLOR = 0x3399ff;
|
||||
int _color; ///User specified color for helping to label parts
|
||||
|
||||
const Part* masterPart() const;
|
||||
Part* masterPart();
|
||||
const Part* redirectPart() const;
|
||||
Part* redirectPart();
|
||||
|
||||
public:
|
||||
Part(Score* = 0);
|
||||
void initFromInstrTemplate(const InstrumentTemplate*);
|
||||
|
@ -97,17 +92,6 @@ class Part final : public ScoreElement {
|
|||
|
||||
void setStaves(int);
|
||||
|
||||
double volume() const;
|
||||
void setVolume(double volume);
|
||||
bool mute() const;
|
||||
void setMute(bool mute);
|
||||
|
||||
double reverb() const;
|
||||
void setReverb(double);
|
||||
double chorus() const;
|
||||
void setChorus(double);
|
||||
double pan() const;
|
||||
void setPan(double pan);
|
||||
int midiProgram() const;
|
||||
void setMidiProgram(int, int bank = 0);
|
||||
|
||||
|
@ -144,6 +128,9 @@ class Part final : public ScoreElement {
|
|||
bool hasTabStaff();
|
||||
bool hasDrumStaff();
|
||||
|
||||
const Part* masterPart() const;
|
||||
Part* masterPart();
|
||||
|
||||
// Allows not reading the same instrument twice on importing 2.X scores.
|
||||
// TODO: do we need instruments info in parts at all?
|
||||
friend void readPart206(Part*, XmlReader&);
|
||||
|
|
|
@ -202,16 +202,11 @@ static constexpr PropertyMetaData propertyList[] = {
|
|||
{ Pid::LINE_VISIBLE, true, "lineVisible", P_TYPE::BOOL, DUMMY_QT_TRANSLATE_NOOP("propertyName", "visible line") },
|
||||
{ Pid::MAG, false, "mag", P_TYPE::REAL, DUMMY_QT_TRANSLATE_NOOP("propertyName", "mag") },
|
||||
{ Pid::USE_DRUMSET, false, "useDrumset", P_TYPE::BOOL, DUMMY_QT_TRANSLATE_NOOP("propertyName", "using drumset") },
|
||||
{ Pid::PART_VOLUME, false, "volume", P_TYPE::INT, DUMMY_QT_TRANSLATE_NOOP("propertyName", "volume") },
|
||||
{ Pid::PART_MUTE, false, "mute", P_TYPE::BOOL, DUMMY_QT_TRANSLATE_NOOP("propertyName", "mute") },
|
||||
{ Pid::PART_PAN, false, "pan", P_TYPE::INT, DUMMY_QT_TRANSLATE_NOOP("propertyName", "pan") },
|
||||
{ Pid::PART_REVERB, false, "reverb", P_TYPE::INT, DUMMY_QT_TRANSLATE_NOOP("propertyName", "reverb") },
|
||||
|
||||
{ Pid::PART_CHORUS, false, "chorus", P_TYPE::INT, DUMMY_QT_TRANSLATE_NOOP("propertyName", "chorus") },
|
||||
{ Pid::DURATION, false, 0, P_TYPE::FRACTION, DUMMY_QT_TRANSLATE_NOOP("propertyName", "duration") },
|
||||
{ Pid::DURATION_TYPE, false, 0, P_TYPE::TDURATION, DUMMY_QT_TRANSLATE_NOOP("propertyName", "duration type") },
|
||||
{ Pid::ROLE, false, "role", P_TYPE::INT, DUMMY_QT_TRANSLATE_NOOP("propertyName", "role") },
|
||||
{ Pid::TRACK, false, 0, P_TYPE::INT, DUMMY_QT_TRANSLATE_NOOP("propertyName", "track") },
|
||||
|
||||
{ Pid::GLISSANDO_STYLE, true, "glissandoStyle", P_TYPE::GLISSANDO_STYLE, DUMMY_QT_TRANSLATE_NOOP("propertyName", "glissando style") },
|
||||
{ Pid::FRET_STRINGS, false, "strings", P_TYPE::INT, DUMMY_QT_TRANSLATE_NOOP("propertyName", "strings") },
|
||||
{ Pid::FRET_FRETS, false, "frets", P_TYPE::INT, DUMMY_QT_TRANSLATE_NOOP("propertyName", "frets") },
|
||||
|
|
|
@ -220,16 +220,11 @@ enum class Pid {
|
|||
LINE_VISIBLE,
|
||||
MAG,
|
||||
USE_DRUMSET,
|
||||
PART_VOLUME,
|
||||
PART_MUTE,
|
||||
PART_PAN,
|
||||
PART_REVERB,
|
||||
|
||||
PART_CHORUS,
|
||||
DURATION,
|
||||
DURATION_TYPE,
|
||||
ROLE,
|
||||
TRACK,
|
||||
|
||||
GLISSANDO_STYLE,
|
||||
FRET_STRINGS,
|
||||
FRET_FRETS,
|
||||
|
|
|
@ -3721,13 +3721,13 @@ ChordRest* Score::findCRinStaff(int tick, int staffIdx) const
|
|||
|
||||
void MasterScore::setSoloMute()
|
||||
{
|
||||
for (int i = 0; i < _midiMapping.size(); i++) {
|
||||
Channel* b = _midiMapping[i].articulation;
|
||||
for (unsigned i = 0; i < _midiMapping.size(); i++) {
|
||||
Channel* b = _midiMapping[i].articulation();
|
||||
if (b->solo()) {
|
||||
b->setSoloMute(false);
|
||||
for (int j = 0; j < _midiMapping.size(); j++) {
|
||||
Channel* a = _midiMapping[j].articulation;
|
||||
bool sameMidiMapping = _midiMapping[i].port == _midiMapping[j].port && _midiMapping[i].channel == _midiMapping[j].channel;
|
||||
for (unsigned j = 0; j < _midiMapping.size(); j++) {
|
||||
Channel* a = _midiMapping[j].articulation();
|
||||
bool sameMidiMapping = _midiMapping[i].port() == _midiMapping[j].port() && _midiMapping[i].channel() == _midiMapping[j].channel();
|
||||
a->setSoloMute((i != j && !a->solo() && !sameMidiMapping));
|
||||
a->setSolo(i == j || a->solo() || sameMidiMapping);
|
||||
}
|
||||
|
@ -4445,6 +4445,37 @@ void MasterScore::setLayoutAll()
|
|||
_cmdState.setTick(measures()->last() ? measures()->last()->endTick() : 0);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// setPlaybackScore
|
||||
//---------------------------------------------------------
|
||||
|
||||
void MasterScore::setPlaybackScore(Score* score)
|
||||
{
|
||||
if (_playbackScore == score)
|
||||
return;
|
||||
|
||||
_playbackScore = score;
|
||||
_playbackSettingsLinks.clear();
|
||||
|
||||
if (!_playbackScore)
|
||||
return;
|
||||
|
||||
for (MidiMapping& mm : _midiMapping)
|
||||
mm.articulation()->setSoloMute(true);
|
||||
for (Part* part : score->parts()) {
|
||||
for (auto& i : *part->instruments()) {
|
||||
Instrument* instr = i.second;
|
||||
for (Channel* ch : instr->channel()) {
|
||||
Channel* pChannel = playbackChannel(ch);
|
||||
Q_ASSERT(pChannel);
|
||||
if (!pChannel)
|
||||
continue;
|
||||
_playbackSettingsLinks.emplace_back(pChannel, ch, /* excerpt */ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// setLayout
|
||||
//---------------------------------------------------------
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "config.h"
|
||||
#include "input.h"
|
||||
#include "instrument.h"
|
||||
#include "select.h"
|
||||
#include "synthesizerstate.h"
|
||||
#include "mscoreview.h"
|
||||
|
@ -159,11 +160,24 @@ class MeasureBaseList {
|
|||
// MidiMapping
|
||||
//---------------------------------------------------------
|
||||
|
||||
struct MidiMapping {
|
||||
Part* part;
|
||||
Channel* articulation;
|
||||
signed char port;
|
||||
signed char channel;
|
||||
class MidiMapping {
|
||||
Part* _part;
|
||||
std::unique_ptr<Channel> _articulation;
|
||||
signed char _port;
|
||||
signed char _channel;
|
||||
Channel* masterChannel;
|
||||
PartChannelSettingsLink link;
|
||||
|
||||
MidiMapping() = default; // should be created only within MasterScore
|
||||
friend class MasterScore;
|
||||
|
||||
public:
|
||||
Part* part() { return _part; }
|
||||
const Part* part() const { return _part; }
|
||||
Channel* articulation() { return _articulation.get(); }
|
||||
const Channel* articulation() const { return _articulation.get(); }
|
||||
signed char port() const { return _port; }
|
||||
signed char channel() const { return _channel; }
|
||||
};
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
@ -534,6 +548,8 @@ class Score : public QObject, public ScoreElement {
|
|||
Score();
|
||||
Score(MasterScore*, bool forcePartStyle = true);
|
||||
Score(MasterScore*, const MStyle&);
|
||||
Score(const Score&) = delete;
|
||||
Score& operator=(const Score&) = delete;
|
||||
virtual ~Score();
|
||||
Score* clone();
|
||||
|
||||
|
@ -1186,6 +1202,8 @@ class MasterScore : public Score {
|
|||
TempoMap* _tempomap;
|
||||
RepeatList* _repeatList;
|
||||
QList<Excerpt*> _excerpts;
|
||||
std::vector<PartChannelSettingsLink> _playbackSettingsLinks;
|
||||
Score* _playbackScore = nullptr;
|
||||
Revisions* _revisions;
|
||||
MasterScore* _next { 0 };
|
||||
MasterScore* _prev { 0 };
|
||||
|
@ -1201,7 +1219,7 @@ class MasterScore : public Score {
|
|||
int _midiPortCount { 0 }; // A count of JACK/ALSA midi out ports
|
||||
QQueue<MidiInputEvent> _midiInputQueue; // MIDI events that have yet to be processed
|
||||
std::list<MidiInputEvent> _activeMidiPitches; // MIDI keys currently being held down
|
||||
QList<MidiMapping> _midiMapping;
|
||||
std::vector<MidiMapping> _midiMapping;
|
||||
bool isSimpleMidiMaping; // midi mapping is simple if all ports and channels
|
||||
// don't decrease and don't have gaps
|
||||
QSet<int> occupiedMidiChannels; // each entry is port*16+channel, port range: 0-inf, channel: 0-15
|
||||
|
@ -1209,6 +1227,7 @@ class MasterScore : public Score {
|
|||
|
||||
void parseVersion(const QString&);
|
||||
void reorderMidiMapping();
|
||||
void rebuildExcerptsMidiMapping();
|
||||
void removeDeletedMidiMapping();
|
||||
int updateMidiMapping();
|
||||
|
||||
|
@ -1280,10 +1299,12 @@ class MasterScore : public Score {
|
|||
|
||||
int midiPortCount() const { return _midiPortCount; }
|
||||
void setMidiPortCount(int val) { _midiPortCount = val; }
|
||||
QList<MidiMapping>* midiMapping() { return &_midiMapping; }
|
||||
std::vector<MidiMapping>& midiMapping() { return _midiMapping; }
|
||||
MidiMapping* midiMapping(int channel) { return &_midiMapping[channel]; }
|
||||
int midiPort(int idx) const { return _midiMapping[idx].port; }
|
||||
int midiChannel(int idx) const { return _midiMapping[idx].channel; }
|
||||
void addMidiMapping(Channel* channel, Part* part, int midiPort, int midiChannel);
|
||||
void updateMidiMapping(Channel* channel, Part* part, int midiPort, int midiChannel);
|
||||
int midiPort(int idx) const { return _midiMapping[idx].port(); }
|
||||
int midiChannel(int idx) const { return _midiMapping[idx].channel(); }
|
||||
void rebuildMidiMapping();
|
||||
void checkMidiMapping();
|
||||
bool exportMidiMapping() { return !isSimpleMidiMaping; }
|
||||
|
@ -1297,6 +1318,12 @@ class MasterScore : public Score {
|
|||
void removeExcerpt(Excerpt*);
|
||||
void deleteExcerpt(Excerpt*);
|
||||
|
||||
void setPlaybackScore(Score*);
|
||||
Score* playbackScore() { return _playbackScore; }
|
||||
const Score* playbackScore() const { return _playbackScore; }
|
||||
Channel* playbackChannel(const Channel* c) { return _midiMapping[c->channel()].articulation(); }
|
||||
const Channel* playbackChannel(const Channel* c) const { return _midiMapping[c->channel()].articulation(); }
|
||||
|
||||
QFileInfo* fileInfo() { return &info; }
|
||||
const QFileInfo* fileInfo() const { return &info; }
|
||||
void setName(const QString&);
|
||||
|
|
|
@ -95,13 +95,14 @@ bool MuseScore::saveAudio(Score* score, QIODevice *device, std::function<bool(fl
|
|||
foreach(Part* part, score->parts()) {
|
||||
const InstrumentList* il = part->instruments();
|
||||
for(auto i = il->begin(); i!= il->end(); i++) {
|
||||
for (const Channel* a : i->second->channel()) {
|
||||
for (const Channel* instrChan : i->second->channel()) {
|
||||
const Channel* a = score->masterScore()->playbackChannel(instrChan);
|
||||
a->updateInitList();
|
||||
for (MidiCoreEvent e : a->init) {
|
||||
if (e.type() == ME_INVALID)
|
||||
continue;
|
||||
e.setChannel(a->channel());
|
||||
int syntiIdx = synth->index(score->masterScore()->midiMapping(a->channel())->articulation->synti());
|
||||
int syntiIdx = synth->index(score->masterScore()->midiMapping(a->channel())->articulation()->synti());
|
||||
synth->play(e, syntiIdx);
|
||||
}
|
||||
}
|
||||
|
@ -136,7 +137,7 @@ bool MuseScore::saveAudio(Score* score, QIODevice *device, std::function<bool(fl
|
|||
const NPlayEvent& e = playPos->second;
|
||||
if (e.isChannelEvent()) {
|
||||
int channelIdx = e.channel();
|
||||
Channel* c = score->masterScore()->midiMapping(channelIdx)->articulation;
|
||||
const Channel* c = score->masterScore()->midiMapping(channelIdx)->articulation();
|
||||
if (!c->mute()) {
|
||||
synth->play(e, synth->index(c->synti()));
|
||||
}
|
||||
|
|
|
@ -237,7 +237,8 @@ bool ExportMidi::write(QIODevice* device, bool midiExpandRepeats, bool exportRPN
|
|||
// Pass through the all channels of the instrument
|
||||
// "normal", "pizzicato", "tremolo" for Strings,
|
||||
// "normal", "mute" for Trumpet
|
||||
foreach(const Channel* ch, j->second->channel()) {
|
||||
for (const Channel* instrChan : j->second->channel()) {
|
||||
const Channel* ch = part->masterScore()->playbackChannel(instrChan);
|
||||
char port = part->masterScore()->midiPort(ch->channel());
|
||||
char channel = part->masterScore()->midiChannel(ch->channel());
|
||||
|
||||
|
|
|
@ -5014,7 +5014,7 @@ static void partList(XmlWriter& xml, Score* score, const QList<Part*>& il, MxmlI
|
|||
int instNr = ii.key();
|
||||
int midiPort = part->midiPort() + 1;
|
||||
if (ii.value()->channel().size() > 0)
|
||||
midiPort = score->masterScore()->midiMapping(ii.value()->channel(0)->channel())->port + 1;
|
||||
midiPort = score->masterScore()->midiMapping(ii.value()->channel(0)->channel())->port() + 1;
|
||||
if (midiPort >= 1 && midiPort <= 16)
|
||||
xml.tag(QString("midi-device %1 port=\"%2\"").arg(instrId(idx+1, instNr + 1)).arg(midiPort), "");
|
||||
else
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "musescore.h"
|
||||
#include "parteditbase.h"
|
||||
|
||||
#include "libmscore/excerpt.h"
|
||||
#include "libmscore/score.h"
|
||||
#include "libmscore/part.h"
|
||||
#include "mixer.h"
|
||||
|
@ -177,7 +178,6 @@ void Mixer::keepScrollPosition()
|
|||
_needToKeepScrollPosition = true;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// masterVolumeChanged
|
||||
//---------------------------------------------------------
|
||||
|
@ -197,6 +197,26 @@ void Mixer::masterVolumeChanged(double decibels)
|
|||
masterSpin->blockSignals(false);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// on_partOnlyCheckBox_toggled
|
||||
//---------------------------------------------------------
|
||||
|
||||
void Mixer::on_partOnlyCheckBox_toggled(bool checked)
|
||||
{
|
||||
if (!_activeScore->excerpt())
|
||||
return;
|
||||
|
||||
mscore->setPlayPartOnly(checked);
|
||||
setPlaybackScore(_activeScore->masterScore()->playbackScore());
|
||||
|
||||
// Prevent muted channels from sounding
|
||||
for (const MidiMapping& mm : _activeScore->masterScore()->midiMapping()) {
|
||||
const Channel* ch = mm.articulation();
|
||||
if (ch && (ch->mute() || ch->soloMute()))
|
||||
seq->stopNotes(ch->channel());
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// retranslate
|
||||
//---------------------------------------------------------
|
||||
|
@ -278,10 +298,10 @@ PartEdit* Mixer::getPartAtIndex(int)
|
|||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// setScore
|
||||
// setPlaybackScore
|
||||
//---------------------------------------------------------
|
||||
|
||||
void Mixer::setScore(MasterScore* score)
|
||||
void Mixer::setPlaybackScore(Score* score)
|
||||
{
|
||||
if (_score != score) {
|
||||
_score = score;
|
||||
|
@ -290,6 +310,21 @@ void Mixer::setScore(MasterScore* score)
|
|||
updateTracks();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// setScore
|
||||
//---------------------------------------------------------
|
||||
|
||||
void Mixer::setScore(Score* score)
|
||||
{
|
||||
// No equality check, this function seems to need to cause
|
||||
// mixer update every time it gets called.
|
||||
_activeScore = score;
|
||||
setPlaybackScore(_activeScore->masterScore()->playbackScore());
|
||||
|
||||
partOnlyCheckBox->setChecked(mscore->playPartOnly());
|
||||
partOnlyCheckBox->setEnabled(_activeScore && !_activeScore->isMaster());
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// updateTracks
|
||||
//---------------------------------------------------------
|
||||
|
@ -305,8 +340,8 @@ void Mixer::updateTracks()
|
|||
//If nothing selected, select first available track
|
||||
if (!_score->parts().isEmpty())
|
||||
{
|
||||
selPart = _score->parts()[0];
|
||||
selChan = selPart->instrument(0)->channel(0);
|
||||
selPart = _score->parts()[0]->masterPart();
|
||||
selChan = selPart->instrument(0)->playbackChannel(0, _score->masterScore());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -333,7 +368,8 @@ void Mixer::updateTracks()
|
|||
|
||||
trackAreaLayout->addWidget(trackHolder);
|
||||
|
||||
for (Part* part : _score->parts()) {
|
||||
for (Part* localPart : _score->parts()) {
|
||||
Part* part = localPart->masterPart();
|
||||
//Add per part tracks
|
||||
bool expanded = expandedParts.contains(part);
|
||||
const InstrumentList* il = part->instruments();
|
||||
|
@ -342,7 +378,7 @@ void Mixer::updateTracks()
|
|||
if (!il->empty()) {
|
||||
il->begin();
|
||||
proxyInstr = il->begin()->second;
|
||||
proxyChan = proxyInstr->channel(0);
|
||||
proxyChan = proxyInstr->playbackChannel(0, _score->masterScore());
|
||||
}
|
||||
|
||||
MixerTrackItemPtr mti = std::make_shared<MixerTrackItem>(
|
||||
|
@ -365,7 +401,7 @@ void Mixer::updateTracks()
|
|||
for (auto it = il1->begin(); it != il1->end(); ++it) {
|
||||
Instrument* instr = it->second;
|
||||
for (int i = 0; i < instr->channel().size(); ++i) {
|
||||
Channel *chan = instr->channel()[i];
|
||||
Channel* chan = instr->playbackChannel(i, _score->masterScore());
|
||||
MixerTrackItemPtr mti1 = std::make_shared<MixerTrackItem>(
|
||||
MixerTrackItem::TrackType::CHANNEL, part, instr, chan);
|
||||
// MixerTrackItemPtr mti = new MixerTrackItem(
|
||||
|
@ -467,7 +503,7 @@ void MuseScore::showMixer(bool val)
|
|||
connect(synti, SIGNAL(soundFontChanged()), mixer, SLOT(updateTracks()));
|
||||
connect(mixer, SIGNAL(closed(bool)), a, SLOT(setChecked(bool)));
|
||||
}
|
||||
mixer->setScore(cs->masterScore());
|
||||
mixer->setScore(cs);
|
||||
mixer->setVisible(val);
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,8 @@ class Mixer : public QDockWidget, public Ui::Mixer, public MixerTrackGroup
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
MasterScore* _score;
|
||||
Score* _score = nullptr; // playback score
|
||||
Score* _activeScore = nullptr; // may be a _score itself or its excerpt;
|
||||
QHBoxLayout* trackAreaLayout;
|
||||
EnablePlayForWidget* enablePlay;
|
||||
|
||||
|
@ -84,6 +85,10 @@ class Mixer : public QDockWidget, public Ui::Mixer, public MixerTrackGroup
|
|||
virtual void keyPressEvent(QKeyEvent*) override;
|
||||
void readSettings();
|
||||
void keepScrollPosition();
|
||||
void setPlaybackScore(Score*);
|
||||
|
||||
private slots:
|
||||
void on_partOnlyCheckBox_toggled(bool checked);
|
||||
|
||||
public slots:
|
||||
void updateTracks();
|
||||
|
@ -102,7 +107,7 @@ class Mixer : public QDockWidget, public Ui::Mixer, public MixerTrackGroup
|
|||
|
||||
public:
|
||||
Mixer(QWidget* parent);
|
||||
void setScore(MasterScore*);
|
||||
void setScore(Score*);
|
||||
PartEdit* getPartAtIndex(int index);
|
||||
void writeSettings();
|
||||
void expandToggled(Part* part, bool expanded) override;
|
||||
|
|
|
@ -27,6 +27,13 @@
|
|||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="partOnlyCheckBox">
|
||||
<property name="text">
|
||||
<string>Play part only</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="detailsArea" native="true">
|
||||
<property name="sizePolicy">
|
||||
|
|
|
@ -161,7 +161,7 @@ void MixerDetails::updateFromTrack()
|
|||
Channel* chan = _mti->focusedChan();
|
||||
|
||||
//Check if drumkit
|
||||
bool drum = midiMap->part->instrument()->useDrumset();
|
||||
const bool drum = midiMap->part()->instrument()->useDrumset();
|
||||
drumkitCheck->blockSignals(true);
|
||||
drumkitCheck->setChecked(drum);
|
||||
drumkitCheck->blockSignals(false);
|
||||
|
@ -235,8 +235,8 @@ void MixerDetails::updateFromTrack()
|
|||
chorusSlider->setValue((int)chan->chorus());
|
||||
chorusSpinBox->setValue(chan->chorus());
|
||||
|
||||
portSpinBox->setValue(part->masterScore()->midiMapping(chan->channel())->port + 1);
|
||||
channelSpinBox->setValue(part->masterScore()->midiMapping(chan->channel())->channel + 1);
|
||||
portSpinBox->setValue(part->masterScore()->midiMapping(chan->channel())->port() + 1);
|
||||
channelSpinBox->setValue(part->masterScore()->midiMapping(chan->channel())->channel() + 1);
|
||||
|
||||
trackColorLabel->blockSignals(false);
|
||||
volumeSlider->blockSignals(false);
|
||||
|
@ -351,7 +351,7 @@ void MixerDetails::propertyChanged(Channel::Prop property)
|
|||
return;
|
||||
|
||||
MidiMapping* _midiMap = _mti->midiMap();
|
||||
Channel* chan = _midiMap->articulation;
|
||||
Channel* chan = _midiMap->articulation();
|
||||
|
||||
switch (property) {
|
||||
case Channel::Prop::VOLUME: {
|
||||
|
@ -480,8 +480,8 @@ void MixerDetails::patchChanged(int n)
|
|||
return;
|
||||
}
|
||||
|
||||
Part* part = _mti->midiMap()->part;
|
||||
Channel* channel = _mti->midiMap()->articulation;
|
||||
Part* part = _mti->midiMap()->part();
|
||||
Channel* channel = _mti->midiMap()->articulation();
|
||||
Score* score = part->score();
|
||||
if (score) {
|
||||
score->startCmd();
|
||||
|
@ -552,8 +552,7 @@ void MixerDetails::midiChannelChanged(int)
|
|||
int c = channelSpinBox->value() - 1;
|
||||
|
||||
MidiMapping* midiMap = _mti->midiMap();
|
||||
midiMap->port = p;
|
||||
midiMap->channel = c;
|
||||
part->masterScore()->updateMidiMapping(midiMap->articulation(), part, p, c);
|
||||
|
||||
// channel->updateInitList();
|
||||
part->score()->setInstrumentsChanged(true);
|
||||
|
|
|
@ -52,6 +52,15 @@ Channel *MixerTrackItem::focusedChan()
|
|||
return _chan;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// playbackChannel
|
||||
//---------------------------------------------------------
|
||||
|
||||
Channel* MixerTrackItem::playbackChannel(const Channel* channel)
|
||||
{
|
||||
return _part->masterScore()->playbackChannel(channel);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// color
|
||||
//---------------------------------------------------------
|
||||
|
@ -74,7 +83,8 @@ void MixerTrackItem::setVolume(char value)
|
|||
const InstrumentList* il = _part->instruments();
|
||||
for (auto it = il->begin(); it != il->end(); ++it) {
|
||||
Instrument* instr = it->second;
|
||||
for (Channel *chan: instr->channel()) {
|
||||
for (const Channel* instrChan: instr->channel()) {
|
||||
Channel* chan = playbackChannel(instrChan);
|
||||
if (chan->volume() != value) {
|
||||
chan->setVolume(value);
|
||||
seq->setController(chan->channel(), CTRL_VOLUME, chan->volume());
|
||||
|
@ -104,7 +114,8 @@ void MixerTrackItem::setPan(char value)
|
|||
const InstrumentList* il = _part->instruments();
|
||||
for (auto it = il->begin(); it != il->end(); ++it) {
|
||||
Instrument* instr = it->second;
|
||||
for (Channel *chan: instr->channel()) {
|
||||
for (const Channel* instrChan: instr->channel()) {
|
||||
Channel* chan = playbackChannel(instrChan);
|
||||
if (chan->pan() != value) {
|
||||
chan->setPan(value);
|
||||
seq->setController(chan->channel(), CTRL_PANPOT, chan->pan());
|
||||
|
@ -134,7 +145,8 @@ void MixerTrackItem::setChorus(char value)
|
|||
const InstrumentList* il = _part->instruments();
|
||||
for (auto it = il->begin(); it != il->end(); ++it) {
|
||||
Instrument* instr = it->second;
|
||||
for (Channel *chan: instr->channel()) {
|
||||
for (const Channel* instrChan: instr->channel()) {
|
||||
Channel* chan = playbackChannel(instrChan);
|
||||
if (chan->chorus() != value) {
|
||||
chan->setChorus(value);
|
||||
seq->setController(chan->channel(), CTRL_CHORUS_SEND, chan->chorus());
|
||||
|
@ -164,7 +176,8 @@ void MixerTrackItem::setReverb(char value)
|
|||
const InstrumentList* il = _part->instruments();
|
||||
for (auto it = il->begin(); it != il->end(); ++it) {
|
||||
Instrument* instr = it->second;
|
||||
for (Channel *chan: instr->channel()) {
|
||||
for (const Channel* instrChan: instr->channel()) {
|
||||
Channel* chan = playbackChannel(instrChan);
|
||||
if (chan->reverb() != value) {
|
||||
chan->setReverb(value);
|
||||
seq->setController(chan->channel(), CTRL_REVERB_SEND, chan->reverb());
|
||||
|
@ -194,7 +207,8 @@ void MixerTrackItem::setColor(int valueRgb)
|
|||
const InstrumentList* il = _part->instruments();
|
||||
for (auto it = il->begin(); it != il->end(); ++it) {
|
||||
Instrument* instr = it->second;
|
||||
for (Channel *chan: instr->channel()) {
|
||||
for (const Channel* instrChan: instr->channel()) {
|
||||
Channel* chan = playbackChannel(instrChan);
|
||||
chan->setColor(valueRgb);
|
||||
}
|
||||
}
|
||||
|
@ -214,7 +228,8 @@ void MixerTrackItem::setMute(bool value)
|
|||
const InstrumentList* il = _part->instruments();
|
||||
for (auto it = il->begin(); it != il->end(); ++it) {
|
||||
Instrument* instr = it->second;
|
||||
for (Channel *chan: instr->channel()) {
|
||||
for (const Channel* instrChan: instr->channel()) {
|
||||
Channel* chan = playbackChannel(instrChan);
|
||||
if (value)
|
||||
seq->stopNotes(chan->channel());
|
||||
chan->setMute(value);
|
||||
|
@ -238,7 +253,8 @@ void MixerTrackItem::setSolo(bool value)
|
|||
const InstrumentList* il = _part->instruments();
|
||||
for (auto it = il->begin(); it != il->end(); ++it) {
|
||||
Instrument* instr = it->second;
|
||||
for (Channel *chan: instr->channel()) {
|
||||
for (const Channel* instrChan: instr->channel()) {
|
||||
Channel* chan = playbackChannel(instrChan);
|
||||
chan->setSolo(value);
|
||||
}
|
||||
}
|
||||
|
@ -253,7 +269,8 @@ void MixerTrackItem::setSolo(bool value)
|
|||
const InstrumentList* il = p->instruments();
|
||||
for (auto i = il->begin(); i != il->end(); ++i) {
|
||||
const Instrument* instr = i->second;
|
||||
for (Channel* a : instr->channel()) {
|
||||
for (const Channel* instrChan: instr->channel()) {
|
||||
Channel* a = playbackChannel(instrChan);
|
||||
if (a->solo()) {
|
||||
numSolo++;
|
||||
}
|
||||
|
@ -265,7 +282,8 @@ void MixerTrackItem::setSolo(bool value)
|
|||
const InstrumentList* il = p->instruments();
|
||||
for (auto i = il->begin(); i != il->end(); ++i) {
|
||||
const Instrument* instr = i->second;
|
||||
for (Channel* a : instr->channel()) {
|
||||
for (const Channel* instrChan: instr->channel()) {
|
||||
Channel* a = playbackChannel(instrChan);
|
||||
if (numSolo == 0) {
|
||||
a->setSoloMute(false);
|
||||
}
|
||||
|
|
|
@ -50,6 +50,8 @@ private:
|
|||
Instrument* _instr;
|
||||
Channel* _chan;
|
||||
|
||||
Channel* playbackChannel(const Channel* channel);
|
||||
|
||||
public:
|
||||
MixerTrackItem(TrackType tt, Part* part, Instrument* _instr, Channel* _chan);
|
||||
|
||||
|
|
|
@ -2391,6 +2391,9 @@ void MuseScore::setCurrentScoreView(ScoreView* view)
|
|||
else
|
||||
cs = 0;
|
||||
|
||||
if (cs)
|
||||
cs->masterScore()->setPlaybackScore(_playPartOnly ? cs : cs->masterScore());
|
||||
|
||||
// set midi import panel
|
||||
QString fileName = cs ? cs->importedFilePath() : "";
|
||||
midiPanelOnSwitchToFile(fileName);
|
||||
|
@ -2409,7 +2412,7 @@ void MuseScore::setCurrentScoreView(ScoreView* view)
|
|||
if (selectionWindow)
|
||||
selectionWindow->setScore(cs);
|
||||
if (mixer)
|
||||
mixer->setScore(cs ? cs->masterScore() : nullptr);
|
||||
mixer->setScore(cs);
|
||||
#ifdef OMR
|
||||
if (omrPanel) {
|
||||
if (cv && cv->omrView())
|
||||
|
@ -4377,8 +4380,8 @@ void MuseScore::play(Element* e) const
|
|||
seq->seek(tick);
|
||||
Instrument* instr = part->instrument(tick);
|
||||
for (Note* n : c->notes()) {
|
||||
const Channel* channel = instr->channel(n->subchannel());
|
||||
seq->startNote(channel->channel(), n->ppitch(), 80, n->tuning());
|
||||
const int channel = instr->channel(n->subchannel())->channel();
|
||||
seq->startNote(channel, n->ppitch(), 80, n->tuning());
|
||||
}
|
||||
seq->startNoteTimer(MScore::defaultPlayDuration);
|
||||
}
|
||||
|
@ -4405,8 +4408,8 @@ void MuseScore::play(Element* e, int pitch) const
|
|||
if (tick < 0)
|
||||
tick = 0;
|
||||
Instrument* instr = masterNote->part()->instrument(tick);
|
||||
const Channel* channel = instr->channel(masterNote->subchannel());
|
||||
seq->startNote(channel->channel(), pitch, 80, MScore::defaultPlayDuration, masterNote->tuning());
|
||||
const int channel = instr->channel(masterNote->subchannel())->channel();
|
||||
seq->startNote(channel, pitch, 80, MScore::defaultPlayDuration, masterNote->tuning());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5734,6 +5737,17 @@ void MuseScore::setPlayRepeats(bool repeat)
|
|||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// setPlayPartOnly
|
||||
//---------------------------------------------------------
|
||||
|
||||
void MuseScore::setPlayPartOnly(bool val)
|
||||
{
|
||||
_playPartOnly = val;
|
||||
if (cs)
|
||||
cs->masterScore()->setPlaybackScore(_playPartOnly ? cs : cs->masterScore());
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// createScoreTab
|
||||
//---------------------------------------------------------
|
||||
|
@ -5760,7 +5774,7 @@ void MuseScore::cmd(QAction* a, const QString& cmd)
|
|||
if (cmd == "instruments") {
|
||||
editInstrList();
|
||||
if (mixer)
|
||||
mixer->setScore(cs->masterScore());
|
||||
mixer->setScore(cs);
|
||||
}
|
||||
else if (cmd == "rewind") {
|
||||
if (cs) {
|
||||
|
@ -6245,7 +6259,7 @@ void MuseScore::noteTooShortForTupletDialog()
|
|||
void MuseScore::instrumentChanged()
|
||||
{
|
||||
if (mixer)
|
||||
mixer->setScore(cs->masterScore());
|
||||
mixer->setScore(cs);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
@ -6672,16 +6686,17 @@ bool MuseScore::saveMp3(Score* score, QIODevice* device, bool& wasCanceled)
|
|||
//
|
||||
// init instruments
|
||||
//
|
||||
foreach(Part* part, score->parts()) {
|
||||
for (Part* part : score->parts()) {
|
||||
const InstrumentList* il = part->instruments();
|
||||
for(auto i = il->begin(); i!= il->end(); i++) {
|
||||
for (const Channel* a : i->second->channel()) {
|
||||
for (const Channel* channel : i->second->channel()) {
|
||||
const Channel* a = score->masterScore()->playbackChannel(channel);
|
||||
a->updateInitList();
|
||||
for (MidiCoreEvent e : a->init) {
|
||||
if (e.type() == ME_INVALID)
|
||||
continue;
|
||||
e.setChannel(a->channel());
|
||||
int syntiIdx= synth->index(score->masterScore()->midiMapping(a->channel())->articulation->synti());
|
||||
int syntiIdx= synth->index(score->masterScore()->midiMapping(a->channel())->articulation()->synti());
|
||||
synth->play(e, syntiIdx);
|
||||
}
|
||||
}
|
||||
|
@ -6731,7 +6746,7 @@ bool MuseScore::saveMp3(Score* score, QIODevice* device, bool& wasCanceled)
|
|||
const NPlayEvent& e = playPos->second;
|
||||
if (e.isChannelEvent()) {
|
||||
int channelIdx = e.channel();
|
||||
Channel* c = score->masterScore()->midiMapping(channelIdx)->articulation;
|
||||
Channel* c = score->masterScore()->midiMapping(channelIdx)->articulation();
|
||||
if (!c->mute()) {
|
||||
synth->play(e, synth->index(c->synti()));
|
||||
}
|
||||
|
|
|
@ -238,6 +238,8 @@ class MuseScore : public QMainWindow, public MuseScoreCore {
|
|||
static const std::list<const char*> _allPlaybackControlEntries;
|
||||
std::list<const char*> _playbackControlEntries { _allPlaybackControlEntries };
|
||||
|
||||
bool _playPartOnly = true; // play part only vs. full score
|
||||
|
||||
QVBoxLayout* layout; // main window layout
|
||||
QSplitter* splitter;
|
||||
ScoreTab* tab1;
|
||||
|
@ -847,6 +849,9 @@ class MuseScore : public QMainWindow, public MuseScoreCore {
|
|||
void setPlaybackControlEntries(std::list<const char*> l) { _playbackControlEntries = l; }
|
||||
void populatePlaybackControls();
|
||||
|
||||
bool playPartOnly() const { return _playPartOnly; }
|
||||
void setPlayPartOnly(bool val);
|
||||
|
||||
static void updateUiStyleAndTheme();
|
||||
|
||||
void showError();
|
||||
|
|
|
@ -290,10 +290,10 @@ void MuseScore::oscVolChannel(double val)
|
|||
PathObject* po = (PathObject*) sender();
|
||||
|
||||
int i = po->path().mid(4).toInt() - 1;
|
||||
QList<MidiMapping>* mms = cs->masterScore()->midiMapping();
|
||||
if( i >= 0 && i < mms->size()) {
|
||||
MidiMapping mm = mms->at(i);
|
||||
Channel* channel = mm.articulation;
|
||||
auto& mms = cs->masterScore()->midiMapping();
|
||||
if( i >= 0 && i < int(mms.size())) {
|
||||
MidiMapping& mm = mms[i];
|
||||
Channel* channel = mm.articulation();
|
||||
int iv = lrint(val*127);
|
||||
seq->setController(channel->channel(), CTRL_VOLUME, iv);
|
||||
channel->setVolume(val * 100.0);
|
||||
|
@ -313,10 +313,10 @@ void MuseScore::oscPanChannel(double val)
|
|||
PathObject* po = (PathObject*) sender();
|
||||
|
||||
int i = po->path().mid(4).toInt() - 1;
|
||||
QList<MidiMapping>* mms = cs->masterScore()->midiMapping();
|
||||
if (i >= 0 && i < mms->size()) {
|
||||
MidiMapping mm = mms->at(i);
|
||||
Channel* channel = mm.articulation;
|
||||
auto& mms = cs->masterScore()->midiMapping();
|
||||
if (i >= 0 && i < int(mms.size())) {
|
||||
MidiMapping& mm = mms[i];
|
||||
Channel* channel = mm.articulation();
|
||||
int iv = lrint((val + 1) * 64);
|
||||
seq->setController(channel->channel(), CTRL_PANPOT, iv);
|
||||
channel->setPan(val * 180.0);
|
||||
|
@ -336,10 +336,10 @@ void MuseScore::oscMuteChannel(double val)
|
|||
PathObject* po = (PathObject*) sender();
|
||||
|
||||
int i = po->path().mid(5).toInt() - 1;
|
||||
QList<MidiMapping>* mms = cs->masterScore()->midiMapping();
|
||||
if (i >= 0 && i < mms->size()) {
|
||||
MidiMapping mm = mms->at(i);
|
||||
Channel* channel = mm.articulation;
|
||||
auto& mms = cs->masterScore()->midiMapping();
|
||||
if (i >= 0 && i < int(mms.size())) {
|
||||
MidiMapping& mm = mms[i];
|
||||
Channel* channel = mm.articulation();
|
||||
channel->setMute(val==0.0f ? false : true);
|
||||
if (mixer)
|
||||
mixer->getPartAtIndex(i)->mute->setChecked(channel->mute());
|
||||
|
|
|
@ -113,8 +113,8 @@ void PartEdit::setPart(Part* p, Channel* a)
|
|||
}
|
||||
}
|
||||
_setChecked(drumset, p->instrument()->useDrumset());
|
||||
_setValue(portSpinBox, part->masterScore()->midiMapping(a->channel())->port + 1);
|
||||
_setValue(channelSpinBox, part->masterScore()->midiMapping(a->channel())->channel + 1);
|
||||
_setValue(portSpinBox, part->masterScore()->midiMapping(a->channel())->port() + 1);
|
||||
_setValue(channelSpinBox, part->masterScore()->midiMapping(a->channel())->channel() + 1);
|
||||
|
||||
QHBoxLayout* hb = voiceButtonBox;
|
||||
int idx = 0;
|
||||
|
@ -286,7 +286,8 @@ void PartEdit::soloToggled(bool val, bool syncControls)
|
|||
const InstrumentList* il = p->instruments();
|
||||
for (auto i = il->begin(); i != il->end(); ++i) {
|
||||
const Instrument* instr = i->second;
|
||||
for (Channel* a : instr->channel()) {
|
||||
for (Channel* instrChan : instr->channel()) {
|
||||
Channel* a = part->masterScore()->playbackChannel(instrChan);
|
||||
a->setSoloMute((channel != a && !a->solo()));
|
||||
a->setSolo(channel == a || a->solo());
|
||||
if (a->soloMute())
|
||||
|
@ -302,7 +303,8 @@ void PartEdit::soloToggled(bool val, bool syncControls)
|
|||
const InstrumentList* il = p->instruments();
|
||||
for (auto i = il->begin(); i != il->end(); ++i) {
|
||||
const Instrument* instr = i->second;
|
||||
for (Channel* a : instr->channel()) {
|
||||
for (Channel* instrChan : instr->channel()) {
|
||||
Channel* a = part->masterScore()->playbackChannel(instrChan);
|
||||
if (a->solo()){
|
||||
found = true;
|
||||
break;
|
||||
|
@ -315,7 +317,8 @@ void PartEdit::soloToggled(bool val, bool syncControls)
|
|||
const InstrumentList* il = p->instruments();
|
||||
for (auto i = il->begin(); i != il->end(); ++i) {
|
||||
const Instrument* instr = i->second;
|
||||
for (Channel* a : instr->channel()) {
|
||||
for (Channel* instrChan : instr->channel()) {
|
||||
Channel* a = part->masterScore()->playbackChannel(instrChan);
|
||||
a->setSoloMute(false);
|
||||
a->setSolo(false);
|
||||
}
|
||||
|
@ -428,7 +431,7 @@ void PartEdit::midiChannelChanged(int)
|
|||
int c = channelSpinBox->value() - 1;
|
||||
|
||||
// 1 is for going up, -1 for going down
|
||||
int direction = copysign(1, c - part->masterScore()->midiMapping(channel->channel())->channel);
|
||||
int direction = copysign(1, c - part->masterScore()->midiMapping(channel->channel())->channel());
|
||||
|
||||
// Channel 9 is special for drums
|
||||
if (part->instrument()->useDrumset() && c != 9) {
|
||||
|
@ -484,8 +487,8 @@ void PartEdit::midiChannelChanged(int)
|
|||
QPushButton *assignFreeChannel = msgBox.addButton(tr("Assign next free MIDI channel"), QMessageBox::HelpRole);
|
||||
msgBox.setDefaultButton(QMessageBox::Ok);
|
||||
if (msgBox.exec() == QMessageBox::Cancel) {
|
||||
_setValue(channelSpinBox, part->masterScore()->midiMapping(channel->channel())->channel + 1);
|
||||
_setValue(portSpinBox, part->masterScore()->midiMapping(channel->channel())->port + 1);
|
||||
_setValue(channelSpinBox, part->masterScore()->midiMapping(channel->channel())->channel() + 1);
|
||||
_setValue(portSpinBox, part->masterScore()->midiMapping(channel->channel())->port() + 1);
|
||||
needSync = false;
|
||||
break;
|
||||
}
|
||||
|
@ -495,10 +498,12 @@ void PartEdit::midiChannelChanged(int)
|
|||
break;
|
||||
}
|
||||
// Sync
|
||||
_setValue(channelSpinBox, newChannel % 16 + 1);
|
||||
_setValue(portSpinBox, newChannel / 16 + 1);
|
||||
part->masterScore()->midiMapping(channel->channel())->channel = newChannel % 16;
|
||||
part->masterScore()->midiMapping(channel->channel())->port = newChannel / 16;
|
||||
const int port = newChannel / 16;
|
||||
const int channelNo = newChannel % 16;
|
||||
_setValue(channelSpinBox, channelNo + 1);
|
||||
_setValue(portSpinBox, port + 1);
|
||||
MasterScore* ms = part->masterScore();
|
||||
ms->updateMidiMapping(ms->playbackChannel(channel), part, port, channelNo);
|
||||
channel->setVolume(lrint(pe->volume->value()));
|
||||
channel->setPan(lrint(pe->pan->value()));
|
||||
channel->setReverb(lrint(pe->reverb->value()));
|
||||
|
@ -522,12 +527,14 @@ void PartEdit::midiChannelChanged(int)
|
|||
}
|
||||
channel->updateInitList();
|
||||
if (needSync) {
|
||||
_setValue(channelSpinBox, newChannel % 16 + 1);
|
||||
_setValue(portSpinBox, newChannel / 16 + 1);
|
||||
part->masterScore()->midiMapping(channel->channel())->channel = newChannel % 16;
|
||||
part->masterScore()->midiMapping(channel->channel())->port = newChannel / 16;
|
||||
part->score()->setInstrumentsChanged(true);
|
||||
part->score()->setLayoutAll();
|
||||
const int port = newChannel / 16;
|
||||
const int channelNo = newChannel % 16;
|
||||
_setValue(channelSpinBox, channelNo + 1);
|
||||
_setValue(portSpinBox, port + 1);
|
||||
MasterScore* ms = part->masterScore();
|
||||
ms->updateMidiMapping(ms->playbackChannel(channel), part, port, channelNo);
|
||||
ms->setInstrumentsChanged(true);
|
||||
ms->setLayoutAll();
|
||||
seq->initInstruments();
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -191,11 +191,6 @@ class Element : public Ms::PluginAPI::ScoreElement {
|
|||
API_PROPERTY( lineVisible, LINE_VISIBLE )
|
||||
API_PROPERTY( mag, MAG )
|
||||
API_PROPERTY( useDrumset, USE_DRUMSET )
|
||||
API_PROPERTY( partVolume, PART_VOLUME )
|
||||
API_PROPERTY( partMute, PART_MUTE )
|
||||
API_PROPERTY( partPan, PART_PAN )
|
||||
API_PROPERTY( partReverb, PART_REVERB )
|
||||
API_PROPERTY( partChorus, PART_CHORUS )
|
||||
API_PROPERTY( duration, DURATION )
|
||||
API_PROPERTY( durationType, DURATION_TYPE )
|
||||
API_PROPERTY( role, ROLE )
|
||||
|
|
|
@ -518,7 +518,7 @@ void Seq::playEvent(const NPlayEvent& event, unsigned framePos)
|
|||
if (note) {
|
||||
Staff* staff = note->staff();
|
||||
Instrument* instr = staff->part()->instrument(note->chord()->tick());
|
||||
const Channel* a = instr->channel(note->subchannel());
|
||||
const Channel* a = instr->playbackChannel(note->subchannel(), cs);
|
||||
mute = a->mute() || a->soloMute() || !staff->playbackVoice(note->voice());
|
||||
}
|
||||
if (!mute) {
|
||||
|
@ -968,8 +968,8 @@ void Seq::initInstruments(bool realTime)
|
|||
_driver->updateOutPortCount(maxMidiOutPort + 1);
|
||||
}
|
||||
|
||||
foreach(const MidiMapping& mm, *cs->midiMapping()) {
|
||||
Channel* channel = mm.articulation;
|
||||
for (const MidiMapping& mm : cs->midiMapping()) {
|
||||
const Channel* channel = mm.articulation();
|
||||
for (const MidiCoreEvent& e : channel->init) {
|
||||
if (e.type() == ME_INVALID)
|
||||
continue;
|
||||
|
@ -980,7 +980,7 @@ void Seq::initInstruments(bool realTime)
|
|||
sendEvent(event);
|
||||
}
|
||||
// Setting pitch bend sensitivity to 12 semitones for external synthesizers
|
||||
if ((preferences.getBool(PREF_IO_JACK_USEJACKMIDI) || preferences.getBool(PREF_IO_ALSA_USEALSAAUDIO)) && mm.channel != 9) {
|
||||
if ((preferences.getBool(PREF_IO_JACK_USEJACKMIDI) || preferences.getBool(PREF_IO_ALSA_USEALSAAUDIO)) && mm.channel() != 9) {
|
||||
if (realTime) {
|
||||
putEvent(NPlayEvent(ME_CONTROLLER, channel->channel(), CTRL_LRPN, 0));
|
||||
putEvent(NPlayEvent(ME_CONTROLLER, channel->channel(), CTRL_HRPN, 0));
|
||||
|
@ -1204,7 +1204,7 @@ void Seq::stopNotes(int channel, bool realTime)
|
|||
};
|
||||
// Stop notes in all channels
|
||||
if (channel == -1) {
|
||||
for(int ch = 0; ch < cs->midiMapping()->size(); ch++) {
|
||||
for(int ch = 0; ch < int(cs->midiMapping().size()); ch++) {
|
||||
send(NPlayEvent(ME_CONTROLLER, ch, CTRL_SUSTAIN, 0));
|
||||
send(NPlayEvent(ME_CONTROLLER, ch, CTRL_ALL_NOTES_OFF, 0));
|
||||
if (cs->midiChannel(ch) != 9)
|
||||
|
@ -1423,13 +1423,13 @@ void Seq::putEvent(const NPlayEvent& event, unsigned framePos)
|
|||
if (!cs)
|
||||
return;
|
||||
int channel = event.channel();
|
||||
if (channel >= cs->midiMapping()->size()) {
|
||||
qDebug("bad channel value %d >= %d", channel, cs->midiMapping()->size());
|
||||
if (channel >= int(cs->midiMapping().size())) {
|
||||
qDebug("bad channel value %d >= %d", channel, int(cs->midiMapping().size()));
|
||||
return;
|
||||
}
|
||||
|
||||
// audio
|
||||
int syntiIdx= _synti->index(cs->midiMapping(channel)->articulation->synti());
|
||||
int syntiIdx= _synti->index(cs->midiMapping(channel)->articulation()->synti());
|
||||
_synti->play(event, syntiIdx);
|
||||
|
||||
// midi
|
||||
|
|
|
@ -383,7 +383,7 @@ void StaffTextProperties::channelItemChanged(QTreeWidgetItem* item, QTreeWidgetI
|
|||
|
||||
int channelIdx = item->data(0, Qt::UserRole).toInt();
|
||||
int tick = static_cast<Segment*>(_staffText->parent())->tick();
|
||||
Channel* channel = part->instrument(tick)->channel(channelIdx);
|
||||
const Channel* channel = part->instrument(tick)->channel(channelIdx);
|
||||
QString channelName = channel->name();
|
||||
|
||||
for (const NamedEventList& e : part->instrument(tick)->midiActions()) {
|
||||
|
@ -441,7 +441,7 @@ void StaffTextProperties::saveValues()
|
|||
if (vb[voice][row]->isChecked()) {
|
||||
int idx = channelCombo[row]->currentIndex();
|
||||
int instrId = static_cast<Segment*>(_staffText->parent())->tick();
|
||||
_staffText->setChannelName(voice, part->instrument(instrId)->channel()[idx]->name());
|
||||
_staffText->setChannelName(voice, part->instrument(instrId)->channel(idx)->name());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2837,7 +2837,7 @@ void Timeline::requestInstrumentDialog()
|
|||
QAction* act = getAction("instruments");
|
||||
mscore->cmd(act);
|
||||
if (mscore->getMixer())
|
||||
mscore->getMixer()->setScore(_score->masterScore());
|
||||
mscore->getMixer()->setScore(_score);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue