music21.scale.scala

This module defines classes for representing Scala scale data, including Scala pitch representations, storage, and files.

The Scala format is defined at the following URL: https://www.huygens-fokker.org/scala/scl_format.html

We thank Manuel Op de Coul for allowing us to include the repository (as of May 11, 2011) with music21

Scala files are encoded as latin-1 (ISO-8859) text

Utility functions are also provided to search and find scales in the Scala scale archive. File names can be found with the search() function.

To create a ScalaScale instance, simply provide a root pitch and the name of the scale. Scale names are given as the scala .scl filename.

>>> mbiraScales = scale.scala.search('mbira')
>>> mbiraScales
['mbira_banda.scl', 'mbira_banda2.scl', 'mbira_gondo.scl', 'mbira_kunaka.scl',
 'mbira_kunaka2.scl', 'mbira_mude.scl', 'mbira_mujuru.scl', 'mbira_zimb.scl']

For most people you’ll want to do something like this:

>>> sc = scale.ScalaScale('a4', 'mbira_banda.scl')
>>> [str(p) for p in sc.pitches]
['A4', 'B4(-15c)', 'C#5(-11c)', 'E-5(-7c)', 'E~5(+6c)', 'F#5(+14c)', 'G~5(+1c)', 'B-5(+2c)']

ScalaData

class music21.scale.scala.ScalaData(sourceString=None, fileName=None)

Object representation of data stored in a Scala scale file. This object is used to access Scala information stored in a file. To create a music21 scale with a Scala file, use ScalaScale.

This is not called ScalaScale, as this name clashes with the ScalaScale that uses this object.

>>> import os
>>> sf = scale.scala.ScalaFile()
>>> fp = common.getSourceFilePath() / 'scale' / 'scala' / 'scl' / 'tanaka.scl'
>>> sf.open(fp)
>>> sd = sf.read()

ScaleFile descriptions are converted to unicode.

>>> print(sd.description)
26-note choice system of Shohé Tanaka, Studien i.G.d. reinen Stimmung (1890)
>>> sd.pitchCount
26

Distances from the tonic:

>>> cat = sd.getCentsAboveTonic()
>>> len(cat)
26
>>> list(int(round(x)) for x in cat[0:4])
[71, 92, 112, 182]
>>> sd.pitchValues[0]
<music21.scale.scala.ScalaPitch object at 0x10b16fac8>
>>> sd.pitchValues[0].cents
70.6724...

This will not add up with centsAboveTonic above, due to rounding

>>> adj = sd.getAdjacentCents()
>>> list(int(round(x)) for x in adj[0:4])
[71, 22, 20, 71]

Interval Sequences

>>> intSeq = sd.getIntervalSequence()
>>> intSeq[0:4]
[<music21.interval.Interval m2 (-29c)>,
 <music21.interval.Interval P1 (+22c)>,
 <music21.interval.Interval P1 (+20c)>,
 <music21.interval.Interval m2 (-29c)>]

Tweak the file and be ready to write it back out:

>>> sd.pitchValues[0].cents = 73.25
>>> sd.fileName = 'tanaka2.scl'
>>> sd.description = 'Tweaked version of tanaka.scl'
>>> fs = sd.getFileString()
>>> print(fs)
! tanaka2.scl
!
Tweaked version of tanaka.scl
26
!
73.25
92.17...
111.73...
182.40...

Be sure to reencode fs as latin-1 before writing to disk.

>>> sf.close()

ScalaData methods

ScalaData.getAdjacentCents()

Get cents values between adjacent intervals.

ScalaData.getCentsAboveTonic()

Return a list of cent values above the implied tonic.

ScalaData.getFileString()

Return a unicode-string suitable for writing a Scala file

The unicode string should be encoded in Latin-1 for maximum Scala compatibility.

ScalaData.getIntervalSequence()

Get the scale as a list of Interval objects.

ScalaData.parse()

Parse a scala file delivered as a long string with line breaks

ScalaData.setAdjacentCents(centList)

Given a list of adjacent cent values, create the necessary ScalaPitch objects and update them

ScalaData.setIntervalSequence(iList)

Set the scale from a list of Interval objects.

ScalaFile

class music21.scale.scala.ScalaFile(data=None)

Interface for reading and writing scala files. On reading, returns a ScalaData object.

>>> import os
>>> sf = scale.scala.ScalaFile()
>>> fp = common.getSourceFilePath() / 'scale' / 'scala' / 'scl' / 'tanaka.scl'
>>> sf.open(fp)
>>> sd = sf.read()
>>> sd
<music21.scale.scala.ScalaData object at 0x10b170e10>
>>> sd is sf.data
True
>>> sf.fileName.endswith('tanaka.scl')
True
>>> sd.pitchCount
26
>>> sf.close()

ScalaFile methods

ScalaFile.close()
ScalaFile.open(fp, mode='r')

Open a file for reading

ScalaFile.openFileLike(fileLike)

Assign a file-like object, such as those provided by StringIO, as an open file object.

ScalaFile.read()

Read a file. Note that this calls readstr, which processes all tokens.

If number is given, a work number will be extracted if possible.

ScalaFile.readstr(strSrc)

Read a string and process all Tokens. Returns a ABCHandler instance.

ScalaFile.write()
ScalaFile.writestr()

ScalaPitch

class music21.scale.scala.ScalaPitch(sourceString=None)

Representation of a scala pitch notation

>>> sp = scale.scala.ScalaPitch(' 1066.667 cents')
>>> print(sp.parse())
1066.667
>>> sp = scale.scala.ScalaPitch(' 2/1')
>>> sp.parse()
1200.0
>>> sp.parse('100.0 C#')
100.0
>>> [sp.parse(x) for x in ['89/84', '55/49', '44/37', '63/50', '4/3', '99/70', '442/295',
...     '27/17', '37/22', '98/55', '15/8', '2/1']]
[100.0992..., 199.9798..., 299.9739..., 400.10848..., 498.04499...,
 600.0883..., 699.9976..., 800.9095..., 900.0260...,
 1000.0201..., 1088.2687..., 1200.0]

ScalaPitch methods

ScalaPitch.parse(sourceString=None)

Parse the source string and set self.cents.

Functions

music21.scale.scala.getPaths()

Get all scala scale paths. This is called once or the module and cached as SCALA_PATHS, which should be used instead of calls to this function.

>>> a = scale.scala.getPaths()
>>> len(a) >= 3800
True
music21.scale.scala.parse(target)

Get a ScalaData object from the bundled SCL archive or a file path.

>>> ss = scale.scala.parse('balafon6')
>>> ss.description
'Observed balafon tuning from Burma, Helmholtz/Ellis p. 518, nr.84'
>>> [str(i) for i in ss.getIntervalSequence()]
['<music21.interval.Interval m2 (+14c)>', '<music21.interval.Interval M2 (+36c)>',
'<music21.interval.Interval M2>', '<music21.interval.Interval m2 (+37c)>',
'<music21.interval.Interval M2 (-49c)>', '<music21.interval.Interval M2 (-6c)>',
'<music21.interval.Interval M2 (-36c)>']
>>> scale.scala.parse('incorrectFileName.scl') is None
True
>>> ss = scale.scala.parse('barbourChrom1')
>>> print(ss.description)
Barbour's #1 Chromatic
>>> ss.fileName
'barbour_chrom1.scl'
>>> ss = scale.scala.parse('blackj_gws.scl')
>>> ss.description
'Detempered Blackjack in 1/4 kleismic marvel tuning'
music21.scale.scala.search(target)

Search the scala archive for matches based on a string

>>> mbiraScales = scale.scala.search('mbira')
>>> mbiraScales
['mbira_banda.scl', 'mbira_banda2.scl', 'mbira_gondo.scl', 'mbira_kunaka.scl',
 'mbira_kunaka2.scl', 'mbira_mude.scl', 'mbira_mujuru.scl', 'mbira_zimb.scl']