Monday 28 February 2011

N-tone equal temperament vs Just Intonation

Some swift number-crunching later and I have several tables of relative pitches (relative to the octave) for N-tone equal temperament scales where 12<=N<=35 and Just Intonation. What surprises me the most is how closely to Just Intonation 12-Tone Equal Temperament actually is! The average difference between the ratios of the notes to the octave in 12-TET and JI is 0.006157 to 6dp. Contrast this with 13-TET having 0.014749, the second-least closely fitting scale in of those considered. In fact, the next nearest reasonable scale in 19-TET, closely followed by 22-TET.

Specifically, 12-TET differs by 0.006157, 32-TET by 0.005659, 35-TET by 0.005402, 19-TET by 0.005342, 33-TET by 0.005320, 22-TET by 0.004979, 31-TET by 0.003342 and 34-TET by 0.002679.

You don't want to see the rest of them; they're worse fits than 12-TET and so of little value.

Proof, if any were needed or wanted, that floating point arithmetic is not exact

Well, well, I replaced CSMTransactionVector throughout the codebase with System.Collections.Generic.List and ran the entire suite of system and unit tests. One of the test (just one, out of ~360) failed! And do you know why? It failed because the test was comparing expected floating point results with actual floating point results and we all know that floating point numbers should not be compared.

Anyway, the system test was comparing the following derived values (be amazed at the expected precision!)

Assert.AreEqual(-7347, pos.Quantity);
Assert.AreEqual(64.966093643663939, pos.AveragePrice);
Assert.AreEqual(-477305.88999999897, pos.GrossAmount);
Assert.AreEqual(-477297.82353045908, pos.NetAmount);

and all but the last were succeeding. The last test, the net amount test, was different by 15E-10!! Dunno about you but I'd normally say that they were the same LoL.

Interestingly, though, the upshot of this is that the CSMTransactionVector appears to store its contents in reverse, in the manner of a functional list, I suppose. Reversing my List after loading the data and running all the tests again meets with SUCCESS!!! Well, well, as I said at the beginning of this post!

This makes me ponder on the internals of the CSMTransactionVector. We have already determined that accessing the vector using an enumerator leads to unexpected results, but this means that using the random-access [] operator does some magic too. I wonder what happens when elements are added to the CSMTransactionVector in mid-flow?

Wednesday 23 February 2011

IDisposable and Collections

Ah, joy! The .NET collections don't clean up their contained objects if said objects are IDisposable! Boo! So, if the collection contains IDisposable then these objects need to be Disposed individually before the collection itself is discarded. Some swift googling revealed that others had experienced this issue (see stackoverflow, for example).

Snipped from stackoverflow:

public class DisposableList : List, IDisposable where T : IDisposable
{
#region IDisposable Members

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

public virtual void Dispose(bool disposing)
{
if (disposing)
{
foreach (T type in this)
{
try
{
type.Dispose();
}
finally {/* In case of ObjectDisposedException*/}
}
}
}
#endregion
}

Investigation reveals that CSMInstrument implements IDisposable! Bah! How many of them are scattered throughout the code, also being held in collections?

Tuesday 22 February 2011

chord progressions

I'm wondering if anyone has looked at the mathematics behind chord progressions. I have a list of frequencies in excel....

Dominant - the perfect fifth

Well, I had wondered why, using the standard Western 12-tone scale, that the perfect fifth is, one, so called and, two, such a nice (in a harmonic sense) fit. All can now be revealed.

CSRInstrument::SetModelName

When modifying instruments using the Sophis API, one would normally expect to call Clone_API() first and then modify the instrument accordingly. This is because the instruments are cached locally and to edit them directly is to change them in the cache in a non-thread safe (this is Sophis, remember) way. So, use Clone_API() first.

However, the documentation for SetModelName() says to call Clone afterwards!

Mysteriously, calling Clone after SetModelName resets the modified flag in the object to false. I suppose it's not that mysterious really. Anyway, the upshot of this is that it would appear to be necessary to manually set the modified flag using SetModified(true). Then Save() will actually persist the updated model name to titres!

Note, however, that it is still necessary to call Clone before SetModelName as well! Goodness gracious!

Failure to call Clone after SetModelName results in an exception being thrown from the depths of the Sophis toolkit bearing a message which politely informs one of the need to use Clone afterwards. Just so that you know.