8      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~None7The times are relative to the start time of the bundle and do not need to be ordered. The 1 types are used instead of floating point types, -because the latter ones caused unpredictable 'negative number' errors. .The denominator must always be a power of 10, 8this way we can prevent unlimited grow of denominators. "1make ALSA set the time stamps in incoming events >9Transpose a note event by the given number of semitones. 3Non-note events are returned without modification. IIf by transposition a note leaves the range of representable MIDI notes, then we return Nothing. ?Swap order of keys. 3Non-note events are returned without modification. EIf by reversing a note leaves the range of representable MIDI notes, then we return Nothing. A , > replaceProgram [1,2,3,4] 5 [10,11,12,13]  (True,[10,11,2,13]) C5Interpret program changes as a kind of bank switches .in order to increase the range of instruments :that can be selected via a block of patch select buttons. programAsBanks ns divides the first sum ns instruments into sections of sizes ns!!0, ns!!1, .... HEach program in those sections is interpreted as a bank in a hierarchy, Awhere the lower program numbers are the least significant banks. Programs from sum ns$ on are passed through as they are.  product ns is the number of instruments 'that you can address using this trick. 7In order to avoid overflow it should be less than 128. E.g. programAsBanks [n,m]* interprets subsequent program changes to a (0<=a<n) and n+b (0<=b<m) as a program change to b*n+a. programAsBanks [8,8]! allows to select 64 instruments by 16 program change buttons, whereas programAsBanks [8,4,4] 9allows to address the full range of MIDI 128 instruments !with the same number of buttons. E/Before every note switch to another instrument Caccording to a list of programs given as state of the State monad. CI do not know how to handle multiple channels in a reasonable way. ECurrently I just switch the instrument independent from the channel, Gand send the program switch to the same channel as the beginning note. FThis function extends E. &It reacts on external program changes -by seeking an according program in the list. <This way we can reset the pointer into the instrument list. HHowever the search must be limited in order to prevent an infinite loop ;if we receive a program that is not contained in the list. I)Map NoteOn events to a controller value. EThis way you may play notes via the resonance frequency of a filter. L)Generate notes according to the key set, /where notes for negative and too large indices 5are padded with keys that are transposed by octaves. WCompute  base ** expo approximately to result type  ;such that the result has a denominator which is a power of  digitBase )and a relative precision of numerator of  precision digits with respect to  digitBase-ary numbers. Z See Haskore/ FlipSong FflipSeq m !! n = cross sum of the m-ary representation of n modulo m. For m=2 this yields  http:www.research.att.comcgi-bin access.cgiasnjas sequenceseisA.cgi?Anum=A010060 [ bruijn n k is a sequence with length n^k where cycle (bruijn n k)6 contains all n-ary numbers with k digits as infixes. HThe function computes the lexicographically smallest of such sequences. \%All Bruijn sequences with a certain   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVW  X YZ[\]^_`abcdefihgjknmloqprstuvwxyz{|}~q    !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ Safe-Infered Safe-Infered2intervals within an octave, all starting with a C ;choose two arbitrary notes from an increasing set of notes =choose three arbitrary notes from an increasing set of notes &transpose an interval to begin with C  Safe-Infered &Sends (drain) each event individually Bsince the events in the bundle might be created in a lazy manner. 7This function distinguishes between events from portIn %and events that are generated by us. >Our generated events must also send an echo to the input port in order to break  event_input" and thus trigger their delivery. 4This allows more complex patterns including pauses, 3notes of different lengths and simultaneous notes. 5Automatically changes the value of a MIDI controller every period' seconds according to a periodic wave. The wave function is a mapping from the phase in [0,1) #to a controller value in the range (-1,1). ?The generation of the wave is controlled by a speed controller (minSpeed and maxSpeed are in waves per second), +the modulation depth and the center value. >The center controller is also the one where we emit our wave. 'That is, when modulation depth is zero $then this effect is almost the same 3as forwarding the controller without modification. SThe small difference is, that we emit a controller value at a regular patternMono, "whereas direct control would mean 3that only controller value changes are transfered.   sweep channel B period (speedCtrl, (minSpeed, maxSpeed)) depthCtrl centerCtrl ' (ctrlRange (-1,1) (sin . (2*pi*))) EWe could use the nice Wave abstraction from the synthesizer package, but that'>s a heavy dependency because of multi-parameter type classes. %The function maintains empty bundles &in order to maintain laziness breaks. :These breaks are import for later merging of the streams. 3 runCyclePrograms (map VoiceMsg.toProgram [8..12])  runProgramsAsBanks [8,4,4]  runPattern 0.12 (cycleUp 4)  " runPatternTempo 0.12 (cycleUp 4)  S runPatternTempo 0.2 (PatternMono selectFromOctaveChord (cycle [0,1,2,0,1,2,0,1]))  runPatternTempo 0.1 (PatternPoly selectFromLimittedChord (let pat = [item 0 1] ./ 1 /. [item 1 1] ./ 2 /. [item 1 1] ./ 1 /. [item 0 1] ./ 2 /. pat in 0 /. pat)) -((* Safe-Infered /The list of scheduled triggers must be finite. ,This process cannot drop an incoming event. 4In order to do so, you must write something of type  T a (Maybe b). 6For convenience you could wrap this in something like Ext a b. Here we abuse the  Applicative constraint. Actually we only need pure. *Typical instance for the traversable type t are '[]' and . &Run two stream processor in parallel. We cannot use the Arrow method &&& since we cannot define the first method of the Arrow class.  Consider 'first :: arrow a b -> arrow (c,a) (c,b) and a trigger where  arrow a b generates an event of type b. 4How could we generate additionally an event of type c without having an input event? input is most oftenly of type  TODO: GWe should allow the process to access and modify the ALSA port number. Swap order of keys. BThis is a funny effect and a new challenge to playing a keyboard.   cycleProgramsDefer t -After a note that triggers a program change, we won'!t change the program in the next t seconds. .This is in order to allow chords being played 0and in order to skip accidentally played notes. BAll pressed keys are latched until a key is pressed after a pause (i.e. all keys released). *For aborting the pattern you have to send a  or  message. A key is hold until n! times further keys are pressed. The n*-th pressed key replaces the current one. Try for instance guitar 0.05 0.03. 3This process simulates playing chords on a guitar. 5If you press some keys like C, E, G on the keyboard, Ethen this process figures out what tones would be played on a guitar 4and plays them one after another with short delays. CIf you release the keys then the chord is played in reverse order. AThis simulates the hand going up and down on the guitar strings. KUnfortunatley it is not possible to go up twice or go down twice this way. -The octaves of the pressed keys are ignored. In detail calling guitar collectTime stepTime means: If a key is pressed, /then collect all key-press events for the next  collectTime seconds. MAfter this period, send out a guitar-like chord pattern for the pressed keys with a delay of stepTime between the notes. &Now wait until all keys are released. DNote that in the meantime keys could have been pressed or released. %They are registered, but not played. :If all keys are released then send out the reverse chord. 5On an AllSoundOff message, release all played tones. I don'9t know whether emitted key-events are always consistent. Audio perception trainer Play sets of notes and Alet the human player answer to them according to a given scheme. CRepeat playing the notes sets until the trainee answers correctly. AThen continue with other sequences, maybe more complicated ones. possible tasks: / replay a sequence of pitches on the keyboard: 1 single notes for training abolute pitches, . intervals all with the same base notes, * intervals with different base notes  transpose a set of pitches: ' tranpose to a certain base note, & transpose by a certain interval - play a set of pitches in a different order:  reversed order,  in increasing pitch - replay a set of simultaneously pressed keys 2The difficulty can be increased by not connecting 0the keyboard directly with the sound generator. %This way, the trainee cannot verify, 2how the pressed keys differ from the target keys. =Sometimes it seems that you are catched in an infinite loop. 2This happens if there were too many keys pressed. +The trainer collects all key press events, =not only the ones that occur after the target set is played. /This way you can correct yourself immediately, (before the target is repeatedly played. DThe downside is, that there may be key press events hanging around. ;You can get rid of them by pressing a key again and again, /but slowly, until the target is played, again. 2Then the queue of registered keys should be empty and you can proceed training. &% Safe-Infered!!!!        !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~??@I@gj\,- streamed-0.2Sound.MIDI.ALSA.CommonSound.MIDI.ALSA.GuitarSound.MIDI.ALSA.TrainingSound.MIDI.ALSA.EventListSound.MIDI.ALSA.CausalSound.MIDI.ALSA.CausalExampleTrieBranchLeaf SweepState sweepSpeed sweepDepth sweepCenter sweepPhase PatternPoly IndexNote PatternMonoSelectorKeyQueueKeySetEventDataBundleBundleTime deconsTimeTimeAbsHandlesequclient portPublic portPrivatequeueinitexitwithsetTimeStamping startQueueconnectconnectTimidity connectLLVMconnectSuperCollidersendNotesendKeysendController sendProgramsendModechannelpitchvelocity controllerprogramnormalVelocityconsTimeincTimenano makeEventmakeEcho outputEvent simpleNotesingletonBundleimmediateBundle timeFromStampdefaultTempoCtrl transposereverse setChannelreplaceProgramprogramFromBanksprogramsAsBanks nextProgramtraverseProgramstraverseProgramsSeekreduceNoteVelocitydelayAddcontrollerFromNote eventsFromKeyselectFromLimittedChordselectFromOctaveChordselectFromChordselectFromChordRatio maybePitch increasePitchselectInversion updateChordcontrollerMatch updateDurupdateDurLinearupdateDurExponentialpowerRationalFromFloatitemfractionflipSeqbruijn bruijnAll bruijnAllMap testBruijn testBruijnAll bruijnAllTriefullTrienullTrie deleteWord lookupWord bruijnAllBitscycleUp cycleDownpingPongcrossSum bruijnPat cycleUpAuto cycleDownAuto pingPongAuto crossSumAutobinaryStaccato binaryLegatobinaryAccidentdecomposePositional cycleUpOctaverandomrandomInversionscycleUpInversions inversionsexamplePatternPolyTempo0examplePatternPolyTempo1 checkChannel checkPitchcheckController checkMode checkProgram mergeStable mergeEither TransposegetPitchmapChordToStringchoosePitchForString stringPitchesall intervalstwoNotes threeNotesreverseThreeNotessortThreeNotestransposeTwoNotesPattern patternTempoEventDataTriggerTriggerRegular ioToLazyListinputEventsCore inputEventspairListFromRelativeEvents outputEventsoutputEventBundlesoutputEventBundledmakeTriggerEventmakeTriggerEventsoutputTriggerEventsmergeGeneratedequidistantEventswhirlmergeGeneratedAtoms patternMonopatternMonoTempopatternPolyTemposweepfilter filterSimplemergeprocess processSimplerunWhirlrunDelayrunKeyboardSplitrunKeyboardSplitLowrunKeyboardSplitHighrunCycleProgramsrunProgramsAsBanks runPatternrunPatternTemporunFilterSweepmain TempoControlTlift liftPointmapparalleleitherIntraverseflatten partitionguide guideWithModepatternSerialTempo cycleProgramscycleProgramsDeferlatch groupLatch serialLatchguitartrainer defaultTemporunpassdelay cycleUpTempo cycleUpPolysplit splitPattern serialPatternbinary withGroup groupBinary groupCrossSum groupBruijn groupCycleUp groupRandomgroupRandomInversions filterKeyreleaseAllKeysbaseGHC.RealRational$fCTime $fMonoidTime$fTransposePitch$fPatternPatternPoly$fPatternPatternMono$fTraversableTrigger$fFoldableTrigger$fFunctorTrigger Data.MaybeMaybe midi-0.1.7.1Sound.MIDI.Message.Channel.Mode AllNotesOff AllSoundOff$fTransposePitchChannel$fOrdPitchChannel$fEqPitchChannel $fCategoryT$fMonoidTriggers$fFunctorTriggers