:      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ Wadler's force function + guarantees that the parser does not fail. !Thus it makes parsing more lazy. -However if the original parser fails though, then we get an unrecoverable irrefutable pattern error on .     Wadler's force function  + guarantees that the parser does not fail. !Thus it makes parsing more lazy. -However if the original parser fails though, then we get an unrecoverable irrefutable pattern error on .          %Shift bitwise to the left and right.  The call  toBase n x takes a given number x and  chops it up, @returning its digits in base b. Its output is in the form of a Fbig-endian list of ints. divMod is used because it gives the correct Grounding for negative numbers. Ex. toBytes 1000 -> toBase 256 1000 -> (256*3) + 232 -> [ 3 , 232 ] GGet only n of the least significant bytes of x. If it takes less than >n digits to express x, then fill the extra digits with zeros. GThe fromBase function converts a list of digits in another base into a single base-10 number. fromBase b [x,y,z] = x*b^2 + y*b^1 + z*b^0 Like  but for big numbers. 7It chops the list into blocks of tractable sizes (e.g.  maxBound::Int).  trunc b n* takes the b least significant bits of n.  splitAt b n< splits a number into a tuple: (before bit b, after bit b).   !"#$%&'(  !"#$%&'(  !"#$%&'(?Hugs makes trouble here because it performs UTF-8 conversions. E.g. [255] is output as [195,191] UIt would be easy to replace these routines by FastPackedString(fps).ByteString.Lazy, 2however this introduces a new package dependency. &Types of predefined MIDI controllers.   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~)*+,-/A MIDI problem is that one cannot uniquely map a MIDI key to a frequency. )The frequency depends on the instrument. I don'7t know if the deviations are defined for General MIDI. 8If this applies one could add transposition information to the use patch map. @For now I have chosen a value that leads to the right frequency "for some piano sound in my setup. +The velocity of an ordinary key stroke and the maximum possible velocity. 764 is given as default value by the MIDI specification and thus we map it to 1. 0 is mapped to 0. ,All other values are interpolated linearly. .<Map integral MIDI controller value to floating point value. ;Maximum integral MIDI controller value 127 is mapped to 1. 9Minimum integral MIDI controller value 0 is mapped to 0.   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!  ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!    !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~H;The Key Signature specifies a mode, either major or minor. GThe following enumerated type lists all the keys in order of their key !signatures from flats to sharps. (Cf = 7 flats, Gf = 6 flats ... F = 1 flat, C = 0 flats/sharps, G = 1 sharp, ... Cs = 7 sharps.) Useful for transposition.       !-The datatypes for MIDI Files and MIDI Events "#$%GDefault duration of a whole note, in seconds; and the default SetTempo Fvalue, in microseconds per quarter note. Both express the default of 120 beats per minute. &'An empty MIDI file. ( Show the ! with one event per line, $suited for comparing MIDIFiles with diff. Can this be replaced by Sound.MIDI.Load.showFile? )*+9A hack that changes the velocities by a rational factor. ,Change the time base. -.)Sort MIDI note events lexicographically. "This is to make MIDI files unique /and robust against changes in the computation. 2In principle Performance.merge should handle this $but due to rounding errors in Float @the order of note events still depends on some internal issues. 7The sample rate of MIDI events should be coarse enough to assert unique results. /Old versions of Haskore.Interface.MIDI.Write wrote  and  /once at the beginning of a file in that order. &The current version supports multiple s in a track and thus a # is set immediately before a note. Because of this a  is now always after a . FFor checking equivalence with old MIDI files we can switch this back. H      !"#$%&'()*+,-./H!"      #$&%'(+-,*)./H          !""#$%&'()*+,-./3/The /& monad parses a track of a MIDI File. EIn MIDI, a shortcut is used for long strings of similar MIDI events: FIf a stream of consecutive events all have the same type and channel, Athe type and channel can be omitted for all but the first event. To implement this feature, Rthe parser must keep track of the type and channel of the most recent MIDI Event. This is done by setting an 01 parser, Jwhich parses the data bytes according to the currently active event type. 210345670The main load function. 1289A MIDI file is made of chunks, each of which is either a  header chunk or a  track chunk6. To be correct, it must consist of one header chunk :followed by any number of track chunks, but for robustness's sake we ignore Lany non-header chunks that come before a header chunk. The header tells us 1the number of tracks to come, which is passed to -. :#Check if a chunk contains a track. Like 97, if a chunk is not a track chunk, it is just ignored. ;1There are two ways to mark the end of the track: -The end of the event list and the meta event . 1Thus the end marker is redundant and we remove a  at the end of the track and complain about all s within the event list. <=DParse a chunk, whether a header chunk, a track chunk, or otherwise. *A chunk consists of a four-byte type code  (a header is MThd ; a track is MTrk), ,four bytes for the size of the coming data, and the data itself. >CParse a Header Chunk. A header consists of a format (0, 1, or 2), Cthe number of track chunks to come, and the smallest time division ,to be used in reading the rest of the file. ?EThe division is implemented thus: the most significant bit is 0 if it's "in ticks per quarter note; 1 if it's an SMPTE value. @FA track is a series of events. Parse a track, stopping when the size  is zero. AHEach event is preceded by the delta time: the time in ticks between the Glast event and the current event. Parse a time and an event, ignoring System Exclusive messages. 3BCParse an event, but without a state for the current type of events like in C. CKParse an event. Note that in the case of a regular MIDI Event, the tag is >the status, and we read the first byte of data before we call D. LIn the case of a MIDIEvent with running status, we find out the status from the parser (it'<s been nice enough to keep track of it for us), and the tag that we'-ve already gotten is the first byte of data. ESimpler version of @, used in the Show functions. FGFind out the status (MIDIEvent type and channel) given a byte of data. DParse a MIDI Event. ;Note that since getting the first byte is a little complex ((there are issues with running status), &it has already been handled for us by C. GParse a MetaEvent. HIJJ$ gets a single byte from the input. KLgetN n. returns n characters (bytes) from the input. MNOO, P, Q, and R take 1-, 2-, 3-, or H4-byte numbers from the input (respectively), convert the base-256 data "into a single number, and return. SPQRTVariable-length quantities" are used often in MIDI notation. +They are represented in the following way: VEach byte (containing 8 bits) uses the 7 least significant bits to store information. VThe most significant bit is used to signal whether or not more information is coming. If it's 1, another byte is coming. If it's 0, that byte is the last one. T1 gets a variable-length quantity from the input. UMThe returned list contains only bytes with the most significant bit cleared. &These are digits of a 128-ary number. 4QFunctions to show the decoded contents of a MIDI file in an easy-to-read format. JThis is for debugging purposes and should not be used in production code. VWXThese two functions, the Y and X parsers, 5do not combine directly into a single master parser. 9Rather, they should be used to chop parts of a midi file ;up into chunks of bytes which can be outputted separately. (Chop a MIDI file into chunks returning:  list of  chunk-type-contents pairs; and >* leftover slop (should be empty in correctly formatted file) YZ[\012340123401234]^The ^ accumulates a String. ?For all the usual reasons, the String is represented by ShowS. 5 The function 5 is the main function  for writing ! values to an actual file.  file name 6%Convert a MIDI file to a ByteString. 7$Convert a MIDI file to a ByteString 'while replacing chunk lengths by (-1). (This way writing the file is more lazy. I don',t know whether this is useful for anything, thus simply don' t use it. _`a8b'The following functions encode various ! elements +into the raw data of a standard MIDI file. cdefghijklmnFNumbers of variable size are represented by sequences of 7-bit blocks /tagged (in the top bit) with a bit indicating: (1) that more data follows; or !(0) that this is the last block. opq5678567856789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~9:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~i~}|{zyxwvutsrqponmlkj9hgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9/hgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;::;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghi~}|{zyxwvutsrqponmlkjjklmnopqrstuvwxyz{|}~r  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !" #$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~                     ! " # $ %& ' ( ) * + , - . / 0 1 234566789:&;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuv midi-0.0.7 Sound.MIDI.IOSound.MIDI.EventSound.MIDI.FileSound.MIDI.File.LoadSound.MIDI.File.SaveSound.MIDI.GeneralSound.MIDI.UtilitySound.MIDI.ParserSound.MIDI.ParserStateSound.MIDI.BitSound.MIDI.StringbaseGHC.IO.Handle.FDopenBinaryFile ByteStringwriteBinaryFilestringCharFromBytereadBinaryFilestringByteFromChar Controller Controller7F Controller7E Controller7D Controller7C Controller7B Controller7A Controller79 Controller78 Controller77 Controller76 Controller75 Controller74 Controller73 Controller72 Controller71 Controller70 Controller6F Controller6E Controller6D Controller6C Controller6B Controller6A Controller69 Controller68 Controller67 Controller66RegisteredParameterMSBRegisteredParameterLSBNonRegisteredParameterMSBNonRegisteredParameterLSB DataDecrement DataIncrement PhaserDepth CelesteDepth ChorusDepth TremoloDepthExtDepth Controller5A Controller59 Controller58 Controller57 Controller56 Controller55 Controller54GeneralPurpose8GeneralPurpose7GeneralPurpose6GeneralPurpose5 Controller4F Controller4E Controller4D Controller4C Controller4B Controller4A Controller49 Controller48 Controller47 Controller46Hold2 Controller44 SoftPedal SustenutoPortaSustain Controller3F Controller3E Controller3D Controller3C Controller3B Controller3A Controller39 Controller38 Controller37 Controller36 Controller35 Controller34GeneralPurpose4LSBGeneralPurpose3LSBGeneralPurpose2LSBGeneralPurpose1LSB Controller2F Controller2E Controller2D Controller2C ExpressionLSB PanoramaLSB Controller29 BalanceLSB MainVolumeLSB DataEntryLSBPortamentoTimeLSBFootControlLSB Controller23BreathControlLSB ModulationLSB BankSelectLSB Controller1F Controller1E Controller1D Controller1C Controller1B Controller1A Controller19 Controller18 Controller17 Controller16 Controller15 Controller14GeneralPurpose4MSBGeneralPurpose3MSBGeneralPurpose2MSBGeneralPurpose1MSB Controller0F Controller0E Controller0D Controller0C ExpressionMSB PanoramaMSB Controller09 BalanceMSB MainVolumeMSB DataEntryMSBPortamentoTimeMSBFootControlMSB Controller03BreathControlMSB ModulationMSB BankSelectMSBT MonoAfter PitchBendControl ProgramChange PolyAfterNoteOnNoteOffControllerValuePressurePitchBendRangeChannel fromChannelProgram fromProgramVelocity fromVelocityPitch fromPitchtoPitch toVelocity toProgram toChannel increasePitch subtractPitchzeroKeynormalVelocitymaximumVelocitytoFloatVelocitytoFloatControllerisNoteisNoteOn isNoteOff bankSelect modulation breathControl footControlportamentoTime dataEntry mainVolumebalancepanorama expressiongeneralPurpose1generalPurpose2generalPurpose3generalPurpose4vectorXvectorY bankSelectMSB modulationMSBbreathControlMSBfootControlMSBportamentoTimeMSB dataEntryMSB mainVolumeMSB balanceMSB panoramaMSB expressionMSBgeneralPurpose1MSBgeneralPurpose2MSBgeneralPurpose3MSBgeneralPurpose4MSB bankSelectLSB modulationLSBbreathControlLSBfootControlLSBportamentoTimeLSB dataEntryLSB mainVolumeLSB balanceLSB panoramaLSB expressionLSBgeneralPurpose1LSBgeneralPurpose2LSBgeneralPurpose3LSBgeneralPurpose4LSBsustainporta sustenuto softPedalhold2generalPurpose5generalPurpose6generalPurpose7generalPurpose8extDepth tremoloDepth chorusDepth celesteDepth phaserDepth dataIncrement dataDecrementnonRegisteredParameterLSBnonRegisteredParameterMSBregisteredParameterLSBregisteredParameterMSBModeMinorMajorKeyKeyCsKeyFsKeyBKeyEKeyAKeyDKeyGKeyCKeyFKeyBfKeyEfKeyAfKeyDfKeyGfKeyCf MetaEventUnknownSequencerSpecificKeySigTimeSig SMPTEOffsetSetTempo EndOfTrack MIDIPrefixCuePointMarkerLyric InstrName TrackName Copyright TextEvent SequenceNum SMPTEBits SMPTEFrames SMPTESecs SMPTEMins SMPTEHoursTempoEvent SysExCont SysExStart MIDIEvent ElapsedTime SchedEventTrackDivisionSMPTETicksTypeSerialParallelMixedConsmaybeMIDIEventmaybeMetaEvent defltDurTdefltSTempty showLinesshowTime showEventchangeVelocity resampleTime getTracks sortEventsprogChangeBeforeSetTempofromFile fromStreammaybeFromStreammaybeEventFromStreamshowFiletoFiletoStream toOpenStream eventToStreamDrum OpenTriangle MuteTriangle OpenCuica MuteCuica LowWoodBlock HiWoodBlockClaves LongGuiro ShortGuiro LongWhistle ShortWhistleMaracasCabasaLowAgogo HighAgogo LowTimbale HighTimbaleLowConga OpenHiConga MuteHiCongaLowBongoHiBongo RideCymbal2 Vibraslap CrashCymbal2Cowbell SplashCymbal TambourineRideBell ChineseCymbal RideCymbal1HighTom CrashCymbal1HiMidTom LowMidTom OpenHiHatLowTom PedalHiHat HighFloorTom ClosedHiHat LowFloorTom ElectricSnareHandClap AcousticSnare SideStick BassDrum1AcousticBassDrum InstrumentGunshotApplause Helicopter TelephoneRing BirdTweetSeashore BreathNoiseGuitarFretNoise ReverseCymbal SynthDrum MelodicTom TaikoDrum Woodblock SteelDrumsAgogo TinkleBellShanaiFiddleBagpipeKalimbaKotoShamisenBanjoSitarFX8SciFi FX7Echoes FX6Goblins FX5Brightness FX4Atmosphere FX3Crystal FX2SoundtrackFX1Rain Pad8SweepPad7Halo Pad6Metallic Pad5Bowed Pad4Choir Pad3PolysynthPad2Warm Pad1NewAge Lead8BassLead Lead7Fifths Lead6Voice Lead5Charang Lead4Chiff Lead3Calliope Lead2Sawtooth Lead1SquareOcarinaWhistle Skakuhachi BlownBottlePanFluteRecorderFlutePiccoloClarinetBassoon EnglishHornOboe BaritoneSaxTenorSaxAltoSax SopranoSax SynthBrass2 SynthBrass1 BrassSection FrenchHorn MutedTrumpetTubaTromboneTrumpet OrchestraHit SynthVoice VoiceOohs ChoirAahs SynthStrings2 SynthStrings1StringEnsemble2StringEnsemble1TimpaniOrchestralHarpPizzicatoStringsTremoloStrings ContrabassCelloViolaViolin SynthBass2 SynthBass1 SlapBass2 SlapBass1 FretlessBassElectricBassPickElectricBassFinger AcousticBassGuitarHarmonicsDistortionGuitarOverdrivenGuitarElectricGuitarMutedElectricGuitarCleanElectricGuitarJazzAcousticGuitarSteelAcousticGuitarNylonTangoAccordian Harmonica Accordion ReedOrgan ChurchOrgan RockOrganPercussiveOrgan DrawbarOrganDulcimer TubularBells XylophoneMarimba VibraphoneMusicBox GlockenspielCelestaClavinet HarpsichordElectricPiano2ElectricPiano1 HonkyTonkElectricGrandPianoBrightAcousticPianoAcousticGrandPianoinstrumentNameToPrograminstrumentNamesinstrumentProgramsinstrumentFromPrograminstrumentToPrograminstrumentChannels instruments drumChannel drumProgram drumMinKey drumKeyTable drumFromKey drumToKeydrums enumRandomRboundedEnumRandom chooseEnummapFstmapSndfst3snd3thd3toMaybeswapforce Data.MaybeJust zeroOrMore oneOrMore mtl-1.1.1.0Control.Monad.State.Lazy runStateTStateTshiftLshiftRtoBasetoBytestoHextoOctaltoBits someBytesfromBase fromBytesfromHex fromOctalfromBits replicateBigGHC.List replicatetruncsplitAtunlinesSconcatSrightSleftScentreSrightleftcentrespaces stateToReadS checkRangemaximumControllerValue TrackParser EventParser ByteParser parseEventChunk AlienChunkHeader evalParserparsetrackFromChunkremoveEndOfTrack isEndOfTrackgetChunk getHeader getDivisiongetTrack getSchedEventgetIndividualEventgetEvent getMIDIEvent getPlainTrack decodeStatus getMetaEventgetText toKeyNamegetByteviewLgetN getStringgetBigNget1get2get3get4 getNByteIntgetVar getVarBytes showChunksshowMR getChunks getPlainChunkputEventParsergetEventParser initReadEventOutChunk MIDIWriteroutMFoutputDivision outputTrack outputEventoutputMIDIEventoutChanoutMetaByteStr outMetaStr outMetaList outMetaMWoutputMetaEventoutIntoutStr outByteStr outLenByteStroutVaroutTagoutChunk outOpenChunk