; ================================================================== ; MelloTrn - the Digital Mellotron CAL program ; 2/27/98, (c)1998 Shawn Bulen ; e-mail: bulens@pacbell.net ; web: home.pacbell.net\bulens ; ================================================================== ; ; This CAL program mirrors MIDI notes with a corresponding audio clip of the same tone. ; ; The basic idea here is to have a unique audio sample for each MIDI tone, just like ; a mellotron. ; ; In the late '60s and early '70s, a mellotron was a sort of analog sampler. ; Intended to replace the string section of an orchestra, a mellotron was ; a keyboard that played a recorded track of analog tape for each key. Usually, each ; keypress played back a single tone of a violin string. You could thus simulate ; a string section by playing a chord on the mellotron. ; ; Modern samplers, even good ones, need to mutate the sound to match the ; required pitch. If you don't like to have your source audio mutated, or if you ; can't afford an awesome top-of-the-line sampler, this CAL program may help you. ; I find the tones warmer and more human than sampled tones. ; ; The reason the mellotron was a failure was, of course, part of its charm. Over ; time, the analog tapes which held each key's "sample" stretched, and when ; played back, the notes went sour. (Remember Yes, anyone? King Crimson?) ; ; ================================================================== ; ; To use this program you must: ; 1. Record an audio source track which follows the rules set down below. ; 2. Record a MIDI track. ; 3. Choose an empty target track for your audio. ; 4. Select ONE, single, solitary, lonesome MIDI note from your MIDI track. ; 5. Run this program. It is strongly recommended that you use Key Bindings, ; so you can easily run it multiple times in a row. ; 6. Repeat for each MIDI note which you want mirrored with audio from your ; audio source track. ; ; ================================================================== ; ; Recommendations for setting up your source audio track: ; 1. You record a chromatic scale of your instrument. ; 2. Each tone in the chromatic scale starts perfectly on a measure. ; 3. Each tone is evenly spaced, meaning, each recorded tone uses exactly ; the same number of measures. ; e.g., an E sample starting in measure 2 ; an F sample starting in measure 4 ; a Gb sample starting in measure 6 ; a G sample starting in measure 8, etc. ; 4. Configure the "User Configuration" part of the program with info describing ; your audio track. ; 5. Once everything is tested & works, comment out the prompts... ; ; Key settings in "User Configuration: ; SampStartMeas - Which measure contains the first sample on the audio track. ; (I use 2, so I can slide the audio back & forth if I wanna...) ; SampLenInMeas - Length of audio samples, in measures. ; SampFirstTone - Midi tone corresponding to first audio note on audio track. ; (28 is what I use for the low E on a guitar...) ; SampTickOffset - Offset, in ticks, to reach into the sample (& lop off initial attack). ; (On my recorded electric guitar, 15 seems to hit the peak of ; attack. 50 or so seems to hit an even sustain.) ; ; (Of course, Brian Eno would probably put just about anything in the source audio ; track & let what happens happen...) ; ; ================================================================== ; ; NOTE #1: This program only works on ONE MIDI NOTE AT A TIME, since ; CAL does not allow EditCopy or EditPaste within a forEachEvent loop. (?!?!) ; If the CAL developers let us do EditCopy or EditPaste from within a forEachEvent ; loop, well, that would be a really, really good thing. ; ; NOTE #2: Lord only knows if this program will be supported under new versions of ; CAL, because it is dependent on the old CAL 3.0 paradigm, e.g., TrackSelect. ; My personal belief is that CAL should keep its old "3.0" type edit functions ; in addition to the 4.0 type edit functions. Only by doing so will we be able to ; write wacky programs like this! ; ; NOTE #3: If we ever get access to the audio functions from within CAL, we can ; do things like add special treatments, filters, or fade-in & fade outs for each of ; these audio notes. Or adjust the audio level based on the velocity of the MIDI ; note. Some day, folks, some day! ; ; ================================================================== ; (do ; === Start of User Configuration === ; === Start of User Configuration === ; ID audio target and audio source tracks... (dword PasteToTrk 4) ; REAL track #, to be user friendly. Decremented later... (dword AudioSourceTrk 3) ; REAL track #, to be user friendly. Decremented later... ; Describe audio source track. (dword SampStartMeas 2) ; Which measure contains the first sample on the audio track. (dword SampLenInMeas 2) ; Length of audio samples, in measures. (dword SampFirstTone 28) ; Midi tone corresponding to first audio note on audio track. (dword SampTickOffset 15) ; Offset, in ticks, to reach into the sample (& lop off initial attack). ; User Prompts (if desired... otherwise comment 'em out...) ;(getInt AudioSourceTrk "Audio Source Track?" 1 256) ;(getInt PasteToTrk "Paste To Track?" 1 256) ;(getInt SampStartMeas "Measure containing first sample?" 1 256) ;(getInt SampLenInMeas "Length of sample in measures?" 1 256) ;(getInt SampFirstTone "MIDI tone number of first sample?" 0 255) ;(getInt SampTickOffset "How many ticks into the tone do you wanna start?" 0 255) ; === End of User Configuration === ; === End of User Configuration === ; Decrement back to zero offset number... (-- AudioSourceTrk) (-- PasteToTrk) ; Constants (dword Reps 1) (dword true 1) (dword false 0) (dword ZeroTime 0) ; Work fields, used during conversion of selected midi tone to location of audio sample. (dword SelSampMeas 0) (dword SelSampStartTime 0) (dword SelSampEndTime 0) ; Selected MIDI note info (dword evTime 0) (dword evNote 0) (dword evVel 0) (dword evDuration 0) (dword evCount 0) ; Count of notes selected. ; Save off From & Thru (dword SaveFrom 0) (dword SaveThru 0) ; do a forEachEvent loop... ; It's the only way to get note info... (forEachEvent (do (if (== Event.Kind NOTE) (do (++ evCount) (if (== evCount 2) (do (pause "Too many notes selected. Only Select 1 note!") ) ; end of Count not OK (do (= evTime Event.Time) (= evNote Note.Key) (= evVel Note.Vel) (= evDuration Note.Dur) (= SaveFrom From) (= SaveThru Thru) ) ; end of Count OK )) ; end of count test ) ; end of if event = note test )) ; end of forEachEvent ; NOW for the copy & paste... ; If note selected, work on it... (if (== evCount 1) (do ; Calculate measure in audio track... (= SelSampMeas (- evNote SampFirstTone)) ; Sub note offset from midi note (= SelSampMeas (* SelSampMeas SampLenInMeas)) ; Factor for length of samples... (= SelSampMeas (+ SelSampMeas SampStartMeas)) ; Add starting loc... ; Convert measure to time... (= SelSampStartTime (makeTime SelSampMeas 1 0)) (+= SelSampStartTime SampTickOffset) ; Add tick offset... (= SelSampEndTime (+ SelSampStartTime evDuration)) ; Copy from Audio track (TrackSelect 0 -1) ; deselect all tracks (= From SelSampStartTime) (= Thru SelSampEndTime) (TrackSelect 1 AudioSourceTrk) ; select audio track (EditCopy40 true false false false true false) (TrackSelect 0 AudioSourceTrk) ; deselect audio track ; Paste to designated track... (EditPaste40 evTime PasteToTrk true Reps ZeroTime true true false false false false false true false) ; Restore From & Thru (= From SaveFrom) (= Thru SaveThru) (message "Note processed by MelloTrn.") (delay 250) )) ; end of note selected... (if (== evCount 0) (do (pause "No notes selected.") )) ; end of note selected... ) ; End of program