Skip to content

Add NonTraditional support to KeyData. - #77

Closed
p-groarke wants to merge 1 commit into
webern:masterfrom
p-groarke:nontraditionalkey
Closed

Add NonTraditional support to KeyData.#77
p-groarke wants to merge 1 commit into
webern:masterfrom
p-groarke:nontraditionalkey

Conversation

@p-groarke

@p-groarke p-groarke commented Mar 28, 2020

Copy link
Copy Markdown

Fixes #70

As far as I could tell, this should be enough to support non-traditional keys in api.

However, I couldn't for the life of me figure out your unit test framework :) Could you explain to me how to add some tests for this? ty

Of note

  • Using a vector of PitchData. Maybe you'd rather I add a new "Data" type which only contains step, alter and accidental? NonTraditionalData maybe?
  • Minor tweaks to cmake.
  • No tests yet! PR will stay Draft until I can add some good tests.

Comment thread CMakeLists.txt

# Mx Library
add_library(${PROJECT_NAME} STATIC ${SRC_MX_API} ${SRC_MX_CORE} ${SRC_MX_IMPL} ${SRC_MX_PUGIXML} ${SRC_MX_UTILITY})
add_library(${PROJECT_NAME} STATIC ${HEADERS_MX_API} ${SRC_MX_API} ${SRC_MX_CORE} ${SRC_MX_IMPL} ${SRC_MX_PUGIXML} ${SRC_MX_UTILITY})

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the headers show up in IDE. Makes it much easier to navigate for new devs.

@webern webern Mar 29, 2020

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will probably conflict when #79 lands but just reapply this change.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, I'll rebase once everything is settled for the cmake stuff.

Comment thread CMakeLists.txt
target_link_libraries(MxTest ${PROJECT_NAME})
target_link_libraries(MxTest ${CMAKE_THREAD_LIBS_INIT})
set_property(TARGET MxTest PROPERTY CXX_STANDARD 14)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT MxTest)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes MxTest the default target in MSVC.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

bool nonTraditionalKey;
// The non-tradional accidentals.
// Fill this with your custom accidentals and alters.
std::vector<PitchData> nonTraditionalPitchData;

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe create a new "Data" struct. "NonTraditionalData"?

@webern webern Mar 29, 2020

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had started, or maybe completed this here https://github.com/webern/mx/master/develop...feature/custom-key-signatures

As a reference to how I was thinking about it. Or you could check it out, kick the tires. The main difference is...

Maybe create a new "Data" struct. "NonTraditionalData"?

Yes, I think that would be better than using PitchData.

Some xsd for reference:

	<xs:complexType name="key">
		<xs:annotation>
			<xs:documentation>The key type represents a key signature. Both traditional and non-traditional key signatures are supported. The optional number attribute refers to staff numbers. If absent, the key signature applies to all staves in the part. Key signatures appear at the start of each system unless the print-object attribute has been set to "no".</xs:documentation>
		</xs:annotation>
		<xs:sequence>
			<xs:choice>
				<xs:group ref="traditional-key"/>
				<xs:group ref="non-traditional-key" minOccurs="0" maxOccurs="unbounded"/>
			</xs:choice>
			<xs:element name="key-octave" type="key-octave" minOccurs="0" maxOccurs="unbounded">
				<xs:annotation>
					<xs:documentation>The optional list of key-octave elements is used to specify in which octave each element of the key signature appears.</xs:documentation>
				</xs:annotation>
			</xs:element>
		</xs:sequence>
		<xs:attribute name="number" type="staff-number"/>
		<xs:attributeGroup ref="print-style"/>
		<xs:attributeGroup ref="print-object"/>
	</xs:complexType>
	<xs:group name="non-traditional-key">
		<xs:annotation>
			<xs:documentation>The non-traditional-key group represents a single alteration within a non-traditional key signature. A sequence of these groups makes up a non-traditional key signature</xs:documentation>
		</xs:annotation>
		<xs:sequence>
			<xs:element name="key-step" type="step">
				<xs:annotation>
					<xs:documentation>Non-traditional key signatures can be represented using the Humdrum/Scot concept of a list of altered tones. The key-step element indicates the pitch step to be altered, represented using the same names as in the step element.</xs:documentation>
				</xs:annotation>
			</xs:element>
			<xs:element name="key-alter" type="semitones">
				<xs:annotation>
					<xs:documentation>Non-traditional key signatures can be represented using the Humdrum/Scot concept of a list of altered tones. The key-alter element represents the alteration for a given pitch step, represented with semitones in the same manner as the alter element.</xs:documentation>
				</xs:annotation>
			</xs:element>
			<xs:element name="key-accidental" type="accidental-value" minOccurs="0">
				<xs:annotation>
					<xs:documentation>Non-traditional key signatures can be represented using the Humdrum/Scot concept of a list of altered tones. The key-accidental element indicates the accidental to be displayed in the key signature, represented in the same manner as the accidental element. It is used for disambiguating microtonal accidentals.</xs:documentation>
				</xs:annotation>
			</xs:element>
		</xs:sequence>
	</xs:group>

g = 4,
a = 5,
b = 6,
count,

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine, whatever. :)

PropertiesWriter::PropertiesWriter( const core::PartwiseMeasurePtr& inPartwiseMeasure )
: myProperties{ nullptr }
, myPartwiseMeasure{ inPartwiseMeasure }
, myConverter{}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added converter because its nice.

core::NonTraditionalKeyPtr k = core::makeNonTraditionalKey();
if (p.step == api::Step::count || p.step == api::Step::unspecified)
{
// Would you prefer throw? assert?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what is your standard in terms of "bad things reporting". Continue, throw, assert, format c:/ ?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think just silently fall back to Step::c. If I remember right I only use exceptions/assertions for bugs in the library, not for bad input.

}

if (p.alter != 0) {
k->setKeyAlter(std::make_shared<core::KeyAlter>(core::Semitones{ double(p.alter) }));

@p-groarke p-groarke Mar 28, 2020

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drops support for float semitones :/ Maybe should use doubles in "NonTraditionalData"?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to adapt the int alter and double cents pattern wherever we convert to/from alter double. See #50
Probably what we should do is move the calculations that I did in #50 to the MxConverter thing and use it in both places.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And by using a custom data struct instead of pitchdata, I'll use a double so it doesn't conflict.



void PropertiesWriter::writeTime( const api::TimeSignatureData& value )
void PropertiesWriter::writeTime(const api::TimeSignatureData& value)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops

measure->timeSignature.beatType = 4;
measure->timeSignature.isImplicit = true;
measure->staves.emplace_back( StaffData{} );
measure->keys.emplace_back( KeyData{} );

@p-groarke p-groarke Mar 28, 2020

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I tried adding a test. But this doesn't do anything. I found 2 test files which test KeyData, this and ApiLy43eScoreData. I don't get what this tests.

@webern webern Mar 29, 2020

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just add a new test for this api/KeyDataTest.cpp.

A lot of the really funky names you see in the tests are related to specific test files. ApiLy43eScoreData is probably related to a test file by that name from the Lilypond MusicXML test suite.

@webern webern left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job figuring out how things work!

const auto coreMode = traditionalKey.getMode()->getValue().getValue();
if( coreMode == core::ModeEnum::major )

if (keyType == core::KeyChoice::Choice::traditionalKey) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (keyType == core::KeyChoice::Choice::traditionalKey) {
if( keyType == core::KeyChoice::Choice::traditionalKey )
{

Just a note on the existing style, for better or worse.

keyData.mode = api::KeyMode::unsupported;
api::PitchData p;
p.step = myConverter.convert(k->getKeyStep()->getValue());
p.alter = int(k->getKeyAlter()->getValue().getValue());

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Microtones will need to be handled in semitones (int) and cents (double).

core::NonTraditionalKeyPtr k = core::makeNonTraditionalKey();
if (p.step == api::Step::count || p.step == api::Step::unspecified)
{
// Would you prefer throw? assert?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think just silently fall back to Step::c. If I remember right I only use exceptions/assertions for bugs in the library, not for bad input.

measure->timeSignature.beatType = 4;
measure->timeSignature.isImplicit = true;
measure->staves.emplace_back( StaffData{} );
measure->keys.emplace_back( KeyData{} );

@webern webern Mar 29, 2020

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just add a new test for this api/KeyDataTest.cpp.

A lot of the really funky names you see in the tests are related to specific test files. ApiLy43eScoreData is probably related to a test file by that name from the Lilypond MusicXML test suite.

}

if (p.alter != 0) {
k->setKeyAlter(std::make_shared<core::KeyAlter>(core::Semitones{ double(p.alter) }));

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to adapt the int alter and double cents pattern wherever we convert to/from alter double. See #50
Probably what we should do is move the calculations that I did in #50 to the MxConverter thing and use it in both places.

Comment thread CMakeLists.txt
target_link_libraries(MxTest ${PROJECT_NAME})
target_link_libraries(MxTest ${CMAKE_THREAD_LIBS_INIT})
set_property(TARGET MxTest PROPERTY CXX_STANDARD 14)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT MxTest)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@p-groarke

Copy link
Copy Markdown
Author

closed, fixed by #81

@p-groarke p-groarke closed this Apr 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature] mx::api NonTraditionalKey equivalent

2 participants