The active wokspace

There is always an active Workspace. When maelzel.core is imported a new Workspace is created, which can be retrieved via getWorkspace

[25]:
from maelzel.core import *
from IPython.display import display

w = getWorkspace()
w
[25]:
Workspace(scorestruct=ScoreStruct(3/4, tempo=96), config={'play.instr': '.piano'}, dynamicCurve=DynamicCurve(shape=expon(0.3), mindb=-60.0, maxdb=0.0))

Alternatively the active workspace can be accessed via the active class variable, as Workspace.active

[26]:
w2 = Workspace.active
assert w is w2

The active workspace contains the working environment. The most important attributes encapsulated here are the score structure (.scorestruct, an instance of ScoreStruct) and the configuration (.config, an instance of CoreConfig)

Each new Workspace contains a basic ScoreStruct (4/4, quarter=60) and a copy of the root config

[27]:
w.scorestruct
[27]:

ScoreStruct

Meas. IndexTimesigTempo (quarter note)LabelRehearsalBarlineBeats
03/4961+1+1
1(3/4)1+1+1
...
[28]:
w.config
19 35
[28]:

CoreConfig: maelzel:core


KeyValueTypeDescr
A4442between 10 - 10000Freq. of A4. Normal values are between 440-443, but any value can be used
chordAdjustGainTruetype: boolLimit the gain of a chord according to the number of notes, to prevent clipping. Only applied if the notes don't have an individual amplitude
dynamicCurveDynamicsppp pp p mp mf f ff ffftype: strPossible dynamic steps. A str with all dynamic steps, sorted from soft to loud
dynamicCurveMaxdb0between -160 - 0Amplitude in dB corresponding to the loudest dynamic
dynamicCurveMindb-60between -160 - 0Amplitude in dB corresponding to the softest dynamic
dynamicCurveShapeexpon(0.3)type: strShape used for the converting dynamics to amplitudes. Normally an exponential curve, given as 'expon(exp)', where exp is the exponent used. exp < 1 results in more resolution for soft dynamics
enharmonic.horizontalWeight1type: intWeight of the horizontal dimension (note sequences) when evaluating an enharmonic variant
enharmonic.verticalWeight0.5type: floatWeight of the vertical dimension (chords within a voice) when evaluating an enharmonic variant
fixStringNotenamesFalsetype: boolTrue: pitches given as notenames are fixed at the spelling given. False: they are respelled for better readability within the context. Pitches given as midi notes or frequencies are always respelled
htmlThemelight{dark, light}Theme used when displaying html inside jupyter
jupyterReprShowTruetype: boolRender notation within the html repr within jupyter. If False, .show needs to be called explicitely to render notation
lilypondpathtype: strPath to the lilypond binary. If set, it must be an absolute, existing path. This needs to be set only when using a specific lilypond installation (lilypond is auto-installed if not found, see lilyponddist)
musescorepathtype: strCommand to use when calling MuseScore. For macOS users: it must be an absolute path pointing to the actual binary inside the .app bundle
openImagesInExternalAppFalsetype: boolForce opening images with an external tool, even when inside a Jupyter notebook
play.backenddefault{alsa, auhal, default, jack, pa_cb, portaudio, pulse}backend used for playback
play.defaultAmplitude1.0between 0 - 1Amplitude of a Note/Chord when an amplitude is needed and the object has an undefined amplitude, only used if play.useDynamics if False
play.defaultDynamicf{f, ff, fff, ffff, mf, mp, p, pp, ppp, pppp}Dynamic of a Note/Chord when a dynamic is needed, only used if play.useDynamics is True. Any event with an amplitude will use that value instead
play.engineNamemaelzel.coretype: strName of the play engine used
play.fade0.02type: floatDefault fade time
play.fadeShapecos{cos, linear, scurve}Curve-shape used for fading in/out
play.gain1.0between 0 - 1Default gain used when playing/recording
play.generalMidiSoundfonttype: strPath to a soundfont (sf2 file) with a general midi mapping
play.graceDuration1/14type: (int, float, str)Duration assigned to a gracenote for playback (in quarternotes)
play.instr.pianotype: str | default: sinDefault instrument used for playback. A list of available instruments can be queried via `presetManager.definedPresets()`.
play.numChannels2between 1 - 128Default number of channels (channels can be set explicitely when calling startPlayEngine
play.pitchInterpollinear{cos, linear}Curve shape for interpolating between pitches
play.schedLatency0.05type: floatLatency when scheduling events to ensure time precission
play.soundfontAmpDiv16384type: intA divisor used to scale the amplitude of soundfonts to a range 0-1
play.soundfontFindPeakAOTFalsetype: boolTrue: find the peak of a soundfont to adjust its normalization at the moment an soundfont preset is defined
play.soundfontInterpollinear{cubic, linear}Interpolation used when reading sample data from a soundfont.
play.unschedFadeout0.05type: floatFade out when stopping a note
play.useDynamicsTruetype: boolTrue: any note/chord with a set dynamic will use dynamics to modify its playback amplitude if no explicit amplitude is set
play.verboseFalsetype: boolTrue: outputs extra debugging information regarding playback
quant.beatWeightTempoThresh52type: int
quant.breakBeatsweak{all, none, strong, weak}Level at which to break syncopations. "all": break all syncopations; "weak": break syncopations over weak beats; "strong": only break syncopations at strong beats; "none": don´t break syncopations
quant.complexityhigh{high, highest, low, lowest, medium}Complexity used for notation.
quant.gridWeightNonebetween 0 - 10Weight applied to the time quantization error. Higher values result in more accurate quantization, at the cost of complexity. None sets this value from the complexity preset (quant.complexity)
quant.nestedTupletsNone{False, None, True}True: allow nested tuplets when quantizing. If None, this flag is set by the complexity preset (quant.complexity). Some backends (musescore) can't parse nested tuplets from musicxml atm
quant.nestedTupletsMusicxmlFalsetype: boolFalse: no nested tuplets are used for musicxml. Some backends (MuseScore) don't render nested tuplets properly from mxml. Nested tuplets are used for other formats if "quant.nestedTuplets" = True
quant.subdivTempoThresh96type: int
quant.syncopExcludeSymDurs(5, 7, 15)type: tupleDurations with a numerator in this list cannot be placed across a beat. A value of (7, 15), for example, excludes double and trippled dotted notes
quant.syncopMaxAsymmetry3between 1 - 99Max. asymmetry of a syncopation. For notes across beats, this sets the max. allowed asymmetry across the beat, as a ratio longest:shortest part across the beat. A note exactly across the beat has an asymmetry of 1
quant.syncopMinFraction1/6type: (str, float, Rational)Min. duration of a syncopation as a ratio of the beat. Any syncopation shorter is broken and its parts tied, to prevent complex syncopations
quant.syncopPartMinFraction1/10type: strMin. duration of any part of a syncopation, as a fraction of the beat. A syncopation consistings of two parts, one left and one right to the beat boundary
rec.blockingTruetype: boolShould recording be blocking or should be done async?
rec.extratime0.0between 0.0 - infDefault extratime added when recording
rec.ksmps64{1, 16, 32, 64, 128, 256}Samples per cycle when rendering offline (passed as ksmps to csound)
rec.numChannels2between 1 - 128Number of channels when rendering to disk
rec.pathtype: strPath used to save output files when rendering offline. If not given the default can be queried via `recordPath`
rec.sr44100{44100, 48000, 88200, 96000, 192000}Sample rate used when rendering offline
rec.verboseFalsetype: boolShow debug output when calling csound as a subprocess
reprDurationAsFractionTruetype: boolShow durations as fractions instead of floats
reprShowFreqFalsetype: boolShow frequency when printing a Note in the console
reprUnicodeAccidentalsTrue{False, full, simple, True}Use unicode accidentals for representation of notes
reprUnicodeFractionsFalsetype: boolShow fractions (for durations/offsets) as unicode glyphs. Not all fonts have support for this
semitoneDivisions4{1, 2, 4}Number of divisions/semitone used for notation (2=quarter-tones, 4=eighth-tones)
show.absOffsetWhenDetachedFalsetype: boolWhen showing an object which has a parent but is shown detached from it, shouldthe absolute offset be used?
show.arpeggiateChordauto{auto, False, True}Display chords as an arpeggio. In auto mode, only arpeggiate when needed
show.arpeggioDuration0.5type: floatDuration used for individual notes when rendering a chord as arpeggio
show.autoClefChangesTruetype: boolTrue: add clef changes to a quantized part if needed. Otherwise, one clef is determined for each part and is not changed along the part.
show.backendlilypond{lilypond, musicxml}Method used when rendering notation
show.cacheImagesTruetype: boolTrue: cache rendered images. Set it to False for debugging. call `resetImageCache()` to reset manually
show.centSep,type: strSeparator used when displaying multiple cents deviation (in a chord)
show.centsTruetype: boolShow cents deviation as text when rendering notation
show.centsTextSnap2between 0 - 50Pitches which deviate less than this cents from a quantized pitchdon´t need a text annotation (see `show.cents`)
show.centsTextStylefontsize=6; placement=belowtype: strStyle used for cents annotations. A list of key=value pairs, separated by ;. Keys: fontsize, box (rectangle, square, circle), placement (above, below), italic, bold. Flags don´t need a value. Example: "fontsize=12; italic; box=rectangle"
show.clefChangesWindow1type: intWhen adding automatic clef changes, use this window size (number of elements per evaluation)
show.clefSimplify0.0between 0 - 10000Simplifies automatic clef changes. Use higher values to limit clef changes
show.clipNoteheadShapesquare{cluster, cross, normal, rectangle, rhombus, slash, square, triangle}Notehead shape to use for clips
show.dynamicFromAmplitudeFalsetype: boolTrue: when rendering notation, if an object has an amplitude and does not have an explicit dynamic, add a dynamic according to the amplitude
show.flagStylestraight{flat, normal, straight}Flag style, at the moment only valid in lilypond
show.formatpng{pdf, png, repr}Used when no explicit format is passed to .show
show.glissHideTiedNotesTruetype: boolHide tied notes which are part of a glissando
show.glissLineThickness2{1, 2, 3, 4}Line thikness when rendering glissandi. The value is abstract and it isup to the renderer to interpret it
show.glissLineTypesolid{solid, wavy}Default line type for glissandi
show.glissStemlessFalsetype: boolWhen the end pitch of a gliss. is shown as gracenote, make this stemless
show.hideRedundantDynamicsTruetype: boolHide redundant dynamics within a voice
show.horizontalSpacemedium{default, large, medium, small, xlarge}Hint to adjust horizontal spacing. The actual result depends on the backend and the format used.
show.jupyterMaxImageWidth1000type: intMax. width in pixels for images displayed in a jupyter notebook
show.keepClefBias2.0type: floatThe higher this value, the more likely it is to keep the previous clef during automatic clef changes
show.labelStylefontsize=9; placement=abovetype: strText size used for labelsA list of key=value pairs, separated by ;. Keys: fontsize, box (rectangle, square, circle), placement (above, below), italic, bold. Flags don´t need a value. Example: "fontsize=12; italic; box=rectangle"
show.lilypondGlissMinLength5type: intMin. length of a glissando in points. Increase this value if gliss. linesare not shown or are too short if a gliss. collides with dots or accidentals
show.lilypondPngStaffsizeScale1.5type: floatFactor applied to the staffsize when rendering to png via lilypond. Useful if rendered images appear too small in a jupyter notebook
show.measureLabelStylebox=rectangle; fontsize=12type: strStyle for measure annotations. A list of key=value pairs separated by ;. Keys: fontsize, box (rectangle, square, circle), placement (above, below), italic, bold. Flags don´t need a value. Example: "fontsize=12; italic; box=rectangle"
show.musicxmlFontScaling1.0type: floatScaling factor applied to font sizes when rendering to musicxml
show.pageMarginMillim4between 0 - 1000Page margin in mm
show.pageOrientationportrait{landscape, portrait}Page orientation when rendering to pdf
show.pageSizea4{a2, a3, a4}Page size when rendering to pdf
show.pngResolution200{100, 200, 300, 600, 1200}DPI used when rendering to png
show.proportionalDuration1/24type: strWhen using proportional spacing, the lower this value, the longer the space taken by each note. This corresponds 1:1 to the value as used by lilypond. See also: https://lilypond.org/doc/v2.23/Documentation/notation/proportional-notation
show.referenceStaffsize12.0type: floatStaff size used as a reference to convert between staff size and scaling factor. This allows to use staff size as a general way to indicate the scale of a score, independent of the backend
show.rehearsalMarkStylebox=rectangle; fontsize=13; boldtype: strStyle for rehearsal marks. A list of key=value pairs, separated by ;. Keys: fontsize, box (rectangle, square, circle), placement (above, below), italic, bold. Flags don´t need a value. Example: "fontsize=12; italic; box=rectangle"
show.respellPitchesTruetype: boolTrue: find a suitable enharmonic representation for pitches within their context. False: the canonical form of eachpitch is used, independent of the context
show.scaleFactor0.75type: floatAffects the size of the generated image when using png format
show.scaleFactorMusicxml0.8type: floatApply a scaling factor to images rendered via musicxml
show.spacingnormal{normal, strict, uniform}Kind of spacing used. "normal": traditional spacing; "uniform": proportional spacing with uniform stretching; "strict": proportional spacing with strict placement (clef changes and bar lines don´t add spacing andmight overlap)
show.staffSize10.0type: floatSize of a staff, in points
show.voiceMaxStaves2between 1 - 4Max. number of staves per voice when showing a Voice as notation. Even thougha voice is a sequence of non-simultaneous events (notes, chords, etc.), these canbe exploded over multiple staves
show.warnIfEmptyTruetype: boolTrue: warn if an object did not produce any scoring parts
soundfilePlotHeight3type: intHeight used for plotting soundfiles. This is used, for example, to set the figsize in matplotlib plots used inline within Jupyter.
splitAcceptableDeviation4type: intWhen splitting notes between staves, notes within this range of the split point will be grouped together if they all fit
.enharmonic.150centMicroPenalty20type: int
.enharmonic.debugFalsetype: boolTrue: print debug information while calculating automatic enharmonic spelling
.quant.complexityWeightNonebetween 0 - 10Weight applied to the complexity of the rhythm during quantization. A higher value results in simpler rhythms. None sets this value from the complexity preset (quant.complexity)
.quant.debugFalsetype: boolOutput extra debug info during quantization, showing how different divisions are evaluated by the quantizer
.quant.debugShowNumRows50type: intWhen quantization debugging is turned on this setting limits the number of different quantization possibilities shown
.quant.divisionWeightNonetype: NoneTypeWeight applied to the penalty of the beat divisionHigher values result in simpler subdivisions. None to use the value set by the complexity preset (quant.complexity)
.quant.gridErrorExpNonetype: NoneTypeExponent applied to the grid error. The error is a value between 0-1 showing the grid accuracy for a given quantization (0=perfect timing). A value between 0-1 makes grid errors weight more. None to use the value set by the complexity preset (quant.complexity)
.quant.mergeTupletsDifferentDurFalsetype: bool
.rec.compressionBitrate224type: intdefault bitrate to use when encoding to ogg or mp3
.show.centsTextPlusSignTruetype: boolShow a plus sign for possitive cents deviations
.show.dynamicsResetAfterEmptyMeasureTruetype: bool
.show.dynamicsResetAfterRest1type: int
.show.dynamicsResetTime32between 0 - 999999999When removing redundant dynamics, reset after this number of quarters
.soundfilePlotWidth24type: int

Modifying the active Workspace vs creating a new Workspace

If you are not planning on working on multiple scores simultaneously, the most convenient way to setup your own score structure or to customize the configuration is to modify the active workspace

[7]:
# Reset the scorestruct to the default
w.setScoreStruct()

chain = Chain(r"""
    4C:0.5
    4D:2
    4E:1
""")
chain.show()
chain.rec(nchnls=1)
../_images/notebooks_getWorkspace_8_0.png
[7]:
OfflineRenderer(outfile="/home/em/.local/share/maelzel/recordings/rec-2025-09-26T19:25:01.585.wav", 1 channels, 3.52 secs, 44100 Hz)
Soundfile: '/home/em/.local/share/maelzel/recordings/rec-2025-09-26T19:25:01.585.wav', duration: 3.52, sr: 44100, numchannels: 1)

[9]:
w.setScoreStruct((3, 4), tempo=96)
chain.show()
chain.rec(nchnls=1)

../_images/notebooks_getWorkspace_9_0.png
[9]:
OfflineRenderer(outfile="/home/em/.local/share/maelzel/recordings/rec-2025-09-26T19:25:37.221.wav", 1 channels, 2.21 secs, 44100 Hz)
Soundfile: '/home/em/.local/share/maelzel/recordings/rec-2025-09-26T19:25:37.221.wav', duration: 2.21, sr: 44100, numchannels: 1)

Or one can create an independent Workspace with its own scorestruct:

[11]:
w = Workspace(scorestruct=ScoreStruct((5, 8), tempo=112), active=True)
chain
[11]:
Chain([4C:1/2♩, 4D:2♩, 4E:1♩], dur=3.5)

Deactivating the active Workspace activates the previous workspace (there should always be an active Workspace)

[12]:
w.deactivate()
chain
[12]:
Chain([4C:1/2♩, 4D:2♩, 4E:1♩], dur=3.5)

As a side note, if you just want to test something under a different scorestruct, you can use a ScoreStruct as a context manager. This clones the active Workspace with the given ScoreStruct and activates this newly created Workspace, to deactivate it when to context is exited.

[14]:
with ScoreStruct(r'''
    7/16, 116
    11/16, 48
'''):
    chain.show()
    display(chain.rec(nchnls=1))

../_images/notebooks_getWorkspace_15_0.png
OfflineRenderer(outfile="/home/em/.local/share/maelzel/recordings/rec-2025-09-26T19:27:21.767.wav", 1 channels, 3.11 secs, 44100 Hz)
Soundfile: '/home/em/.local/share/maelzel/recordings/rec-2025-09-26T19:27:21.767.wav', duration: 3.11, sr: 44100, numchannels: 1)

The same is valid for the configuration. You can modify the active Workspace by changing its config, either via setConfig or by directly assigning to .config:

[15]:
chain = Chain(r'''
  C4+15:1
  4Eb-19:0.5
  3B+:1.5
''')
chain
[15]:
Chain([4C+15:1♩, 4E♭-19:1/2♩, 3B+:3/2♩], dur=3)

[19]:
config = CoreConfig(active=True)
config['show.cents'] = False
chain
[19]:
Chain([4C+15:1♩, 4E♭-19:1/2♩, 3B+:3/2♩], dur=3)

A config can also be used as a context manager:

[23]:
with CoreConfig({'show.flagStyle': 'normal'}):
    chain.show()
../_images/notebooks_getWorkspace_20_0.png

Reset the config to the root config

[24]:
CoreConfig.root().activate()
chain
[24]:
Chain([4C+15:1♩, 4E♭-19:1/2♩, 3B+:3/2♩], dur=3)