output to midi file

259 views
Skip to first unread message

geor...@bigpond.net.au

unread,
Dec 10, 2020, 5:11:47 PM12/10/20
to Extempore
How do I output/save the extempore generated midi data to a .midi file?
I want to play that file on other midi players later.
Can it be done in pattern language or in scheme or xtlang?

Regards
George

Ben Swift

unread,
Dec 10, 2020, 6:42:52 PM12/10/20
to extemp...@googlegroups.com
Hi George

There's no canonical representation of a whole "song" (multiple tracks
of notes) in Extempore, and as such there's no built-in library function
for dumping a midi file to disk.

We could add that functionality in
principle, but my sense is that most folks use Extempore for 'note by
note'

Your best bet is to build up the song (or whatever events you wanted in
the midi file) into some sort of data structure, then write that out to
file. With sufficient knowledge of the standard midi file format and
some careful printf-ing, you could write it directly, or (the approach
I'd probably take) you could print it in some sort of readable format
(e.g. json) and then use an existing converter to write the midi file
(e.g. https://github.com/davidgranstrom/json-to-midi).

Hope that helps. I can throw together an example if you need it.

Cheers,
Ben

geor...@bigpond.net.au

unread,
Dec 11, 2020, 6:16:10 AM12/11/20
to Extempore
Thanks Ben.
No. Leave it at that. It was just a thought.
I can see how it doesn't really fit in with what Extenpore is all about.
Regards
George

Michele Pasin

unread,
Dec 11, 2020, 6:28:50 AM12/11/20
to extemp...@googlegroups.com
Hi George, 

This is not exactly what you're asking for I guess, but one method that worked for me for MIDI-recording a 'live' Extempore session is to use an external DAW to do it. 

E.g. I connect Ableton LIVE to Extempore, generate MIDI events in Extempore and use Ableton to play it and record it. Then I can play it back (or export it) using Ableton only. This method will work with any number of midi channels, provided you map them correctly to the channels in the DAW. 





--
You received this message because you are subscribed to the Google Groups "Extempore" group.
To unsubscribe from this group and stop receiving emails from it, send an email to extemporelan...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/extemporelang/ba5b7f9f-bf6a-43ea-968a-109df9afff9cn%40googlegroups.com.

Duncan McGreggor

unread,
Dec 11, 2020, 10:13:28 AM12/11/20
to extemp...@googlegroups.com
George, I want to pile on the wagon that Michele is driving: I've been experimenting with controlling a DAW via OSC while using Extempore to generate the MIDI that the DAW is recording. I'm using a different Lisp from which I do this, but I think I saw examples of OSC clients somewhere in the Extempore source code not too long ago?

Perhaps Ben & Andrew (& others who know!) could share some examples of setting up an OSC client to control a DAWs track/strip arming/recording capabilities from inside Extempore?

d

geor...@bigpond.net.au

unread,
Dec 11, 2020, 2:42:58 PM12/11/20
to Extempore
Wow! This is lots more than I expected.
Thanks Ben Michele and Duncan.
Plenty there to play with. Very interesting.
Regards
George
PS. I like "pile on the wagon ... someone is driving". An expression I've not heard before.
George

Claudio Donaggio

unread,
Dec 11, 2020, 2:47:49 PM12/11/20
to extemp...@googlegroups.com
Hey guys,
I have never used Extempore to control an external device nor a soft synth in a daw(ogic, Ableton or whatever).
Can anyone point me in the right direction to setup Extempore in order to work with midi?
Cheers!

Inviato dal mio dispositivo mobile Huawei


-------- Messaggio originale --------
Oggetto: Re: output to midi file
Da: "geor...@bigpond.net.au"
A: Extempore
CC:

geor...@bigpond.net.au

unread,
Dec 11, 2020, 3:22:13 PM12/11/20
to Extempore
Yes Claudio
That's the bit I need too - connecting extempore to Albeton.
I guess the dsp has to be reset to output midi and Albeton set to read it.
But never done such a thing and could do with some guidance.
Michele I liked your lovely scales piece!
George

Duncan McGreggor

unread,
Dec 11, 2020, 3:41:46 PM12/11/20
to extemp...@googlegroups.com
Getting MIDI running in Extempore is super-easy (I think easier than DSP!) Extempore has its own fork of Portmidi that it builds with (it's also got support for real-time MIDI, but I haven't used that yet). Here's some example code that Ben wrote which "just works" for me:

That one in particular is where I started when controlling a synth in my DAWs (tried successfully in both Ardour and Studio One v4). It's just the output, so it was just what I needed. If you also want to receive MIDI, check out this one, too:

Now, it's been years since I did anything with MIDI (it was always hardware for me, before) so the most difficult part was actually getting my OS setup in such a way that I could get things working (macos' support for MIDI seems very antiintuitive for me, and that took a couple of days to get consistent, repeatable results).

Per my other comment about communicating with a DAW that supports Open Sound Control (like Ardour does), this might be a good starting place (you'll only need the client portion):

Best of luck, and have a ton of fun!!

d

P.S. One last note: the pattern language setup provides MIDI notes as vars with note names, so if you would rather type c#4 instead of 61, you can pull those into your .xtm file with (sys:load "libs/core/pattern-language.xtm")

ETOL Live Coding

unread,
Dec 11, 2020, 4:08:28 PM12/11/20
to extemp...@googlegroups.com
Thanks Duncan,
That's exactly what I needed.
Cheers! 

Jason Levine

unread,
Dec 11, 2020, 4:22:38 PM12/11/20
to extemp...@googlegroups.com
Any space left on the wagon? ok! I'm piling on!

I've used Reaper, Ableton, and now settled with Logic.  I send multi-channel midi and OSC to control various parameters.  It's great to be able to look at a visual representation of my sessions and edit (ssshhh) where necessary.  Setting up OSC is straightforward in Extempore, just follow the OSC101 example.  I will say tho for midi, be careful selecting midi devices by number. If you're like me and have several midi devices, plugging in a new one doesn't guarantee how the device will be numbered, and once you've loaded the wrong midi device you can't always load another one without restarting extempore. 

Good luck!
Jason



--
Jason Levine
Computational artist/musician

geor...@bigpond.net.au

unread,
Dec 12, 2020, 8:26:28 PM12/12/20
to Extempore
Duncan
Running portmidi.xtm while Ableton is open & I get a 'no midi devices detected' message.
What do I have to do to get portmidi to see Ableton as a sink or receiver port?
Not very familiar with Ableton settings etc.
Or is that not how it works?
Regards
George

Duncan McGreggor

unread,
Dec 12, 2020, 9:15:07 PM12/12/20
to extemp...@googlegroups.com
Definitely not the expert on this topic, but I ran into similar issues when I first did this a week or two ago. I don't think I can provide a minimal working set of conditions, but I can give you what I have done that works -- perhaps others can help you pare that down :-)

I'm on macos, and here's what I did at the system level:
* Opened "Audio MIDI Setup"
* Double-clicked on the IAC Driver in the MIDI Studio window
* Made sure that the default IAC Driver was online
* Also: created two new ports: "General MIDI" and "Virtual Keyboard" just to keep things organized for my own intended use

In Ardour I did the following:
* Created a MIDI track
* Added an instrument to it (in my case, the VST plugin for SynthMaster One)
* Went to the mixer view, then the new strip for the synth, clicked the "MIDI source" button (not labeled as such) and selected the "General MIDI" port I created above

In Studio One v4, I did this:
* Created an Instrument track
* Enabled Console view (opens at bottom of the screen)
* Made sure that the "Instruments" view was enabled there
* In the "Instruments" column, added my VST plugin synth
* It automatically created an "external device" for me, so I checked that it had selected the correct system MIDI port that I created above
* Then, in the "Instruments" column where the VST plugin synth was added, there's a little power button -- I clicked that

Then I loaded the portmidi-output.xtm example in Emacs, connected to Extempore, and followed the code. When it came to listing the devices, I just checked to see the ID that had been assigned to the system MIDI port I created above, and used that one.

As you can see, the majority of the steps lie with what's required in the DAW to set up a MIDI device ...

Is any of this helpful for you?

d

Duncan McGreggor

unread,
Dec 12, 2020, 9:17:49 PM12/12/20
to extemp...@googlegroups.com
Oh, sorry -- that was steps and not an explicit answer to your question. I don't know Ableton, but if it's anything like the others, you'll need to add either a physical device or a software synth (a la my use of SynthMaster One and SynthMaster 2.9). Once you have a track that can receive MIDI, then the portmidi capability in Extempore will have something it can send to ...

d

minoru yamaguchi

unread,
Dec 12, 2020, 9:57:36 PM12/12/20
to extemp...@googlegroups.com

I have been playing KONTAKT 6 by extempore via midi connection without any problem, on Mac and Win emacs.

(sys:load "libs/external/portmini.xtm")

then, the processes like Duncan wrote. (setting midi port No. to each instrument of KONTAKT, too)

I hope this will help.

2020年12月13日(日) 11:17 Duncan McGreggor <dun...@mcgreg.gr>:


--
Minoru Yamaguchi

geor...@bigpond.net.au

unread,
Dec 12, 2020, 11:55:29 PM12/12/20
to Extempore

Duncan & others


Duncan’s steps (for Mac OSX) have worked to an extent.

I had forgotten about ‘Audio Midi Setup’.

• Have some input & output midi devices.  


See illustration here


• And I have some Ableton flickerings under 1 Midi and 2 Midi - on Bus 1 Ch1. The little yellow thing flashes when I run ‘midi-loop’ in portmidi-output.xtm. It stops flickering when I undefine ‘midi-loop’.

• The little green one under 3 Audio flickers in response to sounds picked up on MacBook Air builtin mic.


See illustration here


* I’m not hearing anything on headphones.

• Maybe I’m supposed to do something with iSHowU Audio Capture?


See illustration here


• Duncan says “you'll need to add either a physical device or a software synth (a la my use of SynthMaster One and SynthMaster 2.9). Once you have a track that can receive MIDI, then the portmidi capability in Extempore will have something it can send to ...”

• I’ll need help from here ……..

What’s next?

George

Duncan McGreggor

unread,
Dec 13, 2020, 12:27:42 AM12/13/20
to extemp...@googlegroups.com
My guess is that this is solidly in DAW territory, as it seems that, based upon your descriptions, Ableton is getting MIDI data from Extempore (I couldn't see any of your images; they're all protected in Google Drive).

Some things to check:
* Depending upon a DAW's settings, you may need to "arm" a track (for recording) to hear it
* You should also be able to enabled monitoring for the track
* A quick check for these two is to hit "record" and check if you can then hear what you expect
* Check the Ableton docs / forums for enabling MIDI track monitoring when not recording?

They all do this sort of thing a little differently, though most DAWs seem to emulate what various physical multitrack consoles do (e.g., in studios).

Let us know when you have success!

d


geor...@bigpond.net.au

unread,
Dec 13, 2020, 2:48:36 AM12/13/20
to Extempore
I have changed the files to shared with https://groups.google.com/g/extemporelang
I hope that enables you to see them.

Will try "enabling"
George

Michele Pasin

unread,
Dec 13, 2020, 1:30:39 PM12/13/20
to extemp...@googlegroups.com
Hi George, all

The steps on OSx are these for me: 

1. Open up Audio Midi Setup app / click on Show Midi Studio
2. Double click on IAC driver and add a new entry called 'Extempore BUS' (any name would do). Save and close.
3. Restart Ableton LIVE, open preferences and add a Control Surface for extempore. Ensure INPUT sections 'Track' and Remote' are on. 
4. Start Extempore, init MIDI and (pm_print_devices) to see what device number Ableton is on, then do the usual (define *mididevice* (pm_create_output_stream <number>)) 

I'm attaching a couple of screenshots (source files here) cause pictures are always useful. 

PS here's a bunch of midi and miscellaneous utilities I normally load up with Extempore. It's a rather personal collection.. but maybe of use to someone else too :-)  


audio-midi-setup.png
ableton-settings.png





George Wright

unread,
Dec 13, 2020, 2:50:13 PM12/13/20
to extemp...@googlegroups.com
Thanks Michelle.
How did you get the extempore word into the first column?


Also Google groups (I think) used to have a button to attach files & now disappeared.
What’s the best way to share files with the extempore group?
That’s why I have replied to you via my mail app rather than on the group page.

Appreciate very much your detail & help on this midi problem. Up to now I have played only with extempore 
built-in sounds & samples and am new to midi connections of any kind.

George Wright



On 14 Dec 2020, at 5:30 am, Michele Pasin <michel...@gmail.com> wrote:

Hi George, all

The steps on OSx are these for me: 

1. Open up Audio Midi Setup app / click on Show Midi Studio
2. Double click on IAC driver and add a new entry called 'Extempore BUS' (any name would do). Save and close.
3. Restart Ableton LIVE, open preferences and add a Control Surface for extempore. Ensure INPUT sections 'Track' and Remote' are on. 
4. Start Extempore, init MIDI and (pm_print_devices) to see what device number Ableton is on, then do the usual (define *mididevice* (pm_create_output_stream <number>)) 

I'm attaching a couple of screenshots (source files here) cause pictures are always useful. 

PS here's a bunch of midi and miscellaneous utilities I normally load up with Extempore. It's a rather personal collection.. but maybe of use to someone else too :-)  


<audio-midi-setup.png>
<ableton-settings.png>




Michele Pasin

unread,
Dec 16, 2020, 5:33:16 AM12/16/20
to extemp...@googlegroups.com
Hi George, 
 
How did you get the extempore word into the first column?

Good point. In Ableton Live you can you can create your own MIDI mappings script so I did one and named it 'extempore' - as a result the name appears in the dropdown. 

Note: this is an extra step, extempore-live midi communication will work even without the script (using default settings). 

Cheers!
 

geor...@bigpond.net.au

unread,
May 8, 2021, 3:30:03 AM5/8/21
to Extempore
Michele, Duncan, Jason, Minoru
I think I'm beginning to make some sense of this. I finally made a connection between extempore & LIVE and getting some sound out.

Running portmidi-output.xtm I get this:

-- MIDI input devices --

  device id 0 : <PmDeviceInfo: interface=CoreMIDI name=IAC Driver Extempore BUS I/O?:I>

  device id 1 : <PmDeviceInfo: interface=CoreMIDI name=IAC Driver General Midi I/O?:I>

- MIDI output devices --

device id 2 : <PmDeviceInfo: interface=CoreMIDI name=IAC Driver Extempore BUS I/O?:O>

  device id 3 : <PmDeviceInfo: interface=CoreMIDI name=IAC Driver General Midi I/O?:O>

so I changed the output stream to > (define *mout* (pm_create_output_stream 2))

Then I redefine the midi-loop thing sending to output 2 >

(define midi-loop
(lambda (beat dur)
(mplay *mout* (random (list 60 60 60 67 70 74 75)) (random 60 80) dur 2)
(callback (*metro* (+ beat (* .7 dur))) 'midi-loop (+ beat dur) dur)))

(midi-loop (*metro* 'get-beat 4) 1/4)

I notice that the midi signals are coming into channel 3 in LIVE for all instruments. 
(I guess thats because extempore have zero base numbering and LIVE has 1 base?)

I'm chuffed that I got this far.
But I'd like a pointer to what comes next >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Maybe I have to (define *mout0* (pm_create_output_stream 0)) 
and (define *mout1* (pm_create_output_stream 1))
and then set the incoming channels to 1,2,3 and run  a separate midi-loop with (mplay *mout0* ... ... dur 0). etc for each.

Am I on the right track?
Regards
George

Pasin_LIVE_Ch3_connect.png

minoru yamaguchi

unread,
May 8, 2021, 6:57:55 AM5/8/21
to extemp...@googlegroups.com
Hi George, 

I use KONTAKT Player via midi.
   Kontakt Player's settings : 
      Strings = Midi ch 2, 
      Piano  = Midi Ch 3, ....

this is my example ....

(sys:load "libs/external/portmidi.xtm")
(pm_initialize)
(pm_print_devices)

;;--------  shell window  -----
Portmidi successfully initialised.

-- MIDI input devices --

  device id 0 : <PmDeviceInfo: interface=CoreMIDI name= I/O?:I>
  device id 1 : <PmDeviceInfo: interface=CoreMIDI name= I/O?:I>
  device id 2 : <PmDeviceInfo: interface=CoreMIDI name=Kontakt Virtual Output I/O?:I>

-- MIDI output devices --

  device id 3 : <PmDeviceInfo: interface=CoreMIDI name= I/O?:O>
  device id 4 : <PmDeviceInfo: interface=CoreMIDI name= I/O?:O>
;;---------------------


(define *mout2* (pm_create_output_stream 3))
(play-midi-note (now) *mout2* 60 90 (* 3 44100) 1) ; --> Strings sounds
(play-midi-note (now) *mout2* 60 90 (* 3 44100) 2) ; --> Piano sounds

It is enough for you to set midi channel number, the last argument in play-midi-note.

Hope this helps.

minoru yamaguchi



Duncan McGreggor

unread,
May 8, 2021, 4:02:48 PM5/8/21
to extemp...@googlegroups.com
Many of the Extempore MIDI functions/macrods take a channel as an argument, so you can play up to 16 different instruments on one MIDI device using all 16 channels for that device. You just need to set up the tracks in your DAW to accept MIDI from a different channel, and then use the correct channel in Extempore when calling the MIDI function (if you look at Minoru's examples, the channel is the last arg to midi-play-note). Also note that the MIDI channels in Extempore are zero-based, so what your DAW calls channel 1 will, in Extempore, be a 0 passed as an arg to the play-midi-note function ...

d

--
You received this message because you are subscribed to the Google Groups "Extempore" group.
To unsubscribe from this group and stop receiving emails from it, send an email to extemporelan...@googlegroups.com.

geor...@bigpond.net.au

unread,
May 8, 2021, 6:44:51 PM5/8/21
to Extempore
Thanks Minoru & Duncan
Got it!
Create just one output stream to the correct device id
Send the play midi extempore command to one of 16 possible channels in LIVE.

(define *mout* (pm_create_output_stream 2))

;; I set up three loops 0,1 & 2

(define midi-loop0
(lambda (beat dur)
(mplay *mout* (random (list 60 60 60 67 70 74 75)) (random 60 80) dur 0) ; this 0 here means ch1 on LIVE
(callback (*metro* (+ beat (* .5 dur))) 'midi-loop0 (+ beat dur) dur)))

(define midi-loop1
(lambda (beat dur)
(mplay *mout* (random (list 60 60 60 67 70 74 75)) (random 60 80) dur 1) ; this 1 here means ch2 on LIVE
(callback (*metro* (+ beat (* .5 dur))) 'midi-loop1 (+ beat dur) dur)))

(define midi-loop2
(lambda (beat dur)
(mplay *mout* (random (list 60 60 60 67 70 74 75)) (random 60 80) dur 2) ; this 2 here means ch3 on LIVE
(callback (*metro* (+ beat (* .5 dur))) 'midi-loop2 (+ beat dur) dur)))

(midi-loop (*metro* 'get-beat 4) 1/4)
(midi-loop1 (*metro* 'get-beat 8) 1/2)
(midi-loop2 (*metro* 'get-beat 4) 1/1)

In LIVE I have 3 different instruments set to Ch1, Ch2, Ch3
Monitor set to "In" on each.
And that's working nicely!
Pasin_LIVE_conct_fin.png
 Regards
George

minoru yamaguchi

unread,
May 8, 2021, 10:17:02 PM5/8/21
to extemp...@googlegroups.com
Hi George, 

Part 1

>How do I output/save the extempore generated midi data to a .midi file?
>I want to play that file on other midi players later.
>Can it be done in pattern language or in scheme or xtlang?

I think it helps you to record variable name and it's value in any playing
function that used random produced data, pitch, duration etc, then you can
play back with this recorded random data, and more.

;;   Functions to record the data of random playing music.
;;     Usually it is impossible to re-play the music that was made by the random playing func,
;;     but with these functions,  you can just re-play it as your function plyed.
;;     And you can just re-play it to make new phrases you like, you can easly change
;;     the recorded data, then you can use the new changed data in your playing function, too.
;;     Let's make use of the random data, the gift of chance,  !

;; data is stored continuously in a property list
;;  f1 is func name,  p is pitch var, v is vol var
;; (get 'f1 'p) --> (60 64 ..)
;; (get 'f1 'v) --> (80 88 ..) etc
;; property list should be reversed before using it to re-play,
;; because of using cons when making it !!
;;   (get-4play-data f1 p v)
;;      f1 is func name to play something, but anything is ok as long as different from the others,
;;      and p is var for pitch, v is var for volume in f1 in this playing function.
;;      If you would like to record d(duration), add d to argument place like as
;;      (get-4play-data f1 p v d)
;;      If you would like to record just p(pitch valu) only, (get-4play-data f1 p)
(define-macro (get-4play-data . args)
  (let ((a (gensym))) 
    `(let ((fname (car (quote ,args))))
       (map (lambda (,a)
              (let ((dlis (get fname ,a) ))
                (if (eq? dlis '())
                    (put fname ,a (list (eval ,a)))
                    (put fname ,a (cons (eval ,a) dlis)))))
            (cdr (quote ,args))))))


;; reverse property list data, to use correct ordered one
(define-macro (rev-4play-data . args)
  (let ((a (gensym))) 
    `(let ((fname (car (quote ,args))))
       (map (lambda (,a)
              (put fname ,a (reverse (get fname ,a))))
            (cdr (quote ,args))))))

;; clear property list
(define-macro (clear-4play-data . args)
  (let ((a (gensym))) 
    `(let ((fname (car (quote ,args))))
       (map (lambda (,a)
              (put fname ,a '()))
            (cdr (quote ,args))))))

;; print out property list
(define-macro (prt-4play-data . args)
  (let ((a (gensym))) 
    `(let ((fname (car (quote ,args))))
       (map (lambda (,a)
              (println (get fname ,a)))
            (cdr (quote ,args))))))

;; duplicate property list to re-play the tune using "recorded" data
;;   "func name" is added "-dup" in this process, so  fname -> fname-dup
;;   and the same property list
;;   so same as (put 'fname-dup 'p '(60 64))
(define-macro (dup-4play-data . args)
  (let ((a (gensym))) ; to avoid var name confliction, see ../test/macro04.xtm
    `(let* ((fname (car (quote ,args)))
            (dup-name (string->atom
                       (string-append (atom->string fname) "-dup"))))
       (map (lambda (,a)
              (put dup-name ,a (get fname ,a)))
            (cdr (quote ,args))))))


;; assigning each value of property list to variables of playing fuction
;;  using duplicated property list, this is, 'fname-dup' one,
;;  and rotate it every time while loop playing,
;;  of course, original property list is not changed
(define-macro (assign-4play-data . args) ; args is fname p v d aux1 etc
  (let ((a (gensym))) ; to avoid var name confliction, see ../test/macro04.xtm
    `(let* ((fname (car (quote ,args)))
            (dup-name (string->atom
                       (string-append (atom->string fname) "-dup"))))
       (map (lambda (,a)
              (let ((p-lis (get dup-name ,a)))
(eval (list 'set! ,a '(car p-lis)))
                (put dup-name ,a (rotate p-lis -1))))
            (cdr (quote ,args))))))



minoru yamaguchi



minoru yamaguchi

unread,
May 8, 2021, 10:17:51 PM5/8/21
to extemp...@googlegroups.com
Part 2

;; usage ....
;; 1. Make some ordinary playing music function as follows ...

(define play1
  (lambda (beat-n)
    (let ((p (random '(60 62 64 65 67 69)))
          (v 70)
          (d (random '(1 1/2 1/2 1/4))))
      (play-note (*metro* beat-n) fmsynth p v (*metro* 'dur d) .24 .5)
      (callback (*metro* (+ beat-n (* .5 d))) 'play1 (+ beat-n d)))))

(play1 (*metro* 'get-beat))
(define play1 (lambda ()))

;; Now, play1 has no problem to play the random music!  then ..

;; 2. add 2 lines of functions as follows ... in order to record the data
;;    evaluate play1 definition then play the random music and record it,
;;    and stop it when you like.

(define play1
  (lambda (beat-n)
    (let ((p (random '(60 62 64 65 67 69)))
          (v 70)
          (d (random '(1 1/2 1/2 1/4))))

      (get-4play-data play1 p d) ; 1 recording data
      ;; (assign-4play-data play1 p d) ; 2 comment out when recording

      (play-note (*metro* beat-n) fmsynth p v (*metro* 'dur d) .24 .5)
      (callback (*metro* (+ beat-n (* .5 d))) 'play1 (+ beat-n d)))))

(play1 (*metro* 'get-beat))
(define play1 (lambda ()))


;; 3. Ok, the data was stored, then you need to correct the order of data as follows
;;    just once do this !

(rev-4play-data play1 p d)


;; 4. Now re-playing !
;;    Duplicate the recorded data not to destroy the original recorded data order,
;;      when you would like to re-play from the first, do this duplication again !
;;      because this data was rotated as proceeding of playing.
;;    comment out 1, and use 2, then evaluate play1 again as usual
;;    this play1 plays not newly random-ed data but the recorded random data
;;    because 'line 2' assigns the recorded data to the local variables, p d 

(dup-4play-data play1 p d) ; duplicates the data

(define play1 ; same as above play1 except for the commented out line
  (lambda (beat-n)
    (let ((p (random '(60 62 64 65 67 69)))
          (v 70)
          (d (random '(1 1/2 1/2 1/4))))

      ;; (get-4play-data play1 p d) ; 1
      (assign-4play-data play1 p d) ; 2

      (play-note (*metro* beat-n) fmsynth p v (*metro* 'dur d) .24 .5)
      (callback (*metro* (+ beat-n (* .5 d))) 'play1 (+ beat-n d)))))

(play1 (*metro* 'get-beat))
(define play1 (lambda ()))

;; 5. If you would like to print out the recorded data, do this ...

(prt-4play-data play1-dup p d)
;; --> (64 60 60 65 69 60 65 62 65 69 60 65 .....)
;; --> (1 1/2 1 1 1 1/2 1 1/2 1 1/4 1/2 1/2 .....)

;; 6. If you would like to get the data

(get 'play1 'p)
;; returns (64 60 60 65 69 60 65 62 65 69 60 65 .....)

(get 'play1 'd)
;; returns (1 1/2 1 1 1 1/2 1 1/2 1 1/4 1/2 1/2 .....)

(get 'play1-dup 'p) ; or
(prt-4play-data play1-dup p)
;; --> (60 65 62 65 69 60 65 62 60 64 69 .... 64 60) ; dup data was rotated to play it

;; 7. So, you could play tha data you like if you do 
(put 'play1-dup 'p '(60 60 64 67 .... anything you like))

;; 8. clear the old data to re-recording 
(clear-4play-data play1 p d)

minoru yamaguchi



minoru yamaguchi

unread,
May 8, 2021, 10:18:41 PM5/8/21
to extemp...@googlegroups.com
Part 3

;; Chord play is ok, too.
(define ch1
  (lambda (beat-n)
    (let* ((chr-lis (pc:make-chord 48 72 3 (random '((0 4 7) (0 5 9) (7 11 2)))))
           (v 70)
           (d (random '( 1 1 2 2 3))))
      (for-each (lambda (p)
                  ;; (get-4play-data ch1 p d)    ; use this when recording
                  (assign-4play-data ch1 p d) ; use this when re-playing
                  (play-note (*metro* beat-n) fmsynth p v (*metro* 'dur d) .13 .2))
                chr-lis)
      (callback (*metro* (+ beat-n (* .5 d))) 'ch1 (+ beat-n d)))))

(ch1 (*metro* 'get-beat ))
(define ch1 (lambda ()))

(rev-4play-data ch1 p d)
(prt-4play-data ch1 p d)
(dup-4play-data ch1 p d)
;; re-evaluate ch1 after changing comment line, then start again with stored data
(ch1 (*metro* 'get-beat ))

(clear-4play-data ch1 p d)

;; chord play and store not mono pitch but chord list
;;;;;;;;;
;;;;;;;;;;;;;
(define ch2
  (lambda (beat-n)
    (let* ((chr-lis (pc:make-chord 48 72 3 (random '((0 4 7) (0 5 9) (7 11 2)))))
           (v 70)
           (d (random '( 1 1 2 2 3))))
      (get-4play-data ch2 chr-lis d)    ; use this when recording
      ;; (assign-4play-data ch2 chr-lis d) ; use this when re-playing
      (for-each (lambda (p)
                  (play-note (*metro* beat-n) fmsynth p v (*metro* 'dur d) .13 .2))
                chr-lis)
      (callback (*metro* (+ beat-n (* .5 d))) 'ch2 (+ beat-n d)))))


(ch2 (*metro* 'get-beat ))
(define ch2 (lambda ()))

(rev-4play-data ch2 chr-lis d)
(prt-4play-data ch2 chr-lis d)
(dup-4play-data ch2 chr-lis d)
(clear-4play-data ch2 chr-lis d)
(get 'ch2-dup 'chr-lis)
;; re-evaluate ch2 then start again with stored data
(ch2 (*metro* 'get-beat ))

(clear-4play-data ch2 chrlis d)

      
(define ch2
  (lambda (beat-n)
    (let* ((chrlis (pc:make-chord 48 72 3 (random '((0 4 7) (0 5 9) (7 11 2)))))
           (v 70)
           (d (random '( 1 1 2 2 3))))
      ;; (get-4play-data ch2 chrlis d)    ; use this when recording
      (assign-4play-data ch2 chrlis d) ; use this when re-playing
      (println 'chr-lis 'is chrlis)
      (for-each (lambda (p)
                  (play-note (*metro* beat-n) fmsynth p v (*metro* 'dur d) .13 .2))
                chrlis)
      (callback (*metro* (+ beat-n (* .5 d))) 'ch2 (+ beat-n d)))))

(ch2 (*metro* 'get-beat ))
(define ch2 (lambda ()))

(rev-4play-data ch2 chrlis d)
(prt-4play-data ch2 chrlis d)
(dup-4play-data ch2 chrlis d)
;; re-evaluate ch2 then start again with stored data
(ch2 (*metro* 'get-beat ))

(clear-4play-data ch2 chrlis d)

minoru yamaguchi



minoru yamaguchi

unread,
May 8, 2021, 10:19:55 PM5/8/21
to extemp...@googlegroups.com
Part 4

;; when playing func has some playing parts
;;   use some lines as you need 
;;   it's ok to use just one assign function ! this is fun, too.
(define play2 
  (lambda (beat-n)
    (let* ((p (random '(60 62 64 65 67 69)))
           (p2 (pc:relative p (random '(-1 1 2 3 4 5)) '(0 2 4 5 7 9)))
           (v 70)
           (d (random '(1 1 1 1/2 1/2 1/4))))

      ;; (get-4play-data play2 p d)
      ;; (get-4play-data play2 p2)      
      (assign-4play-data play2 p d)
      ;; (assign-4play-data play2 p2)       

      (play-note (*metro* beat-n) fmsynth p v (*metro* 'dur d) .24 .5)
      (play-note (*metro* beat-n) fmsynth p2 v (*metro* 'dur d) .03 .5)
      (callback (*metro* (+ beat-n (* .5 d))) 'play2 (+ beat-n d)))))

(play2 (*metro* 'get-beat))
(define play2 (lambda ()))
(rev-4play-data play2 p d)
(rev-4play-data play2 p2)
(dup-4play-data play2 p d)
(dup-4play-data play2 p2)
(prt-4play-data play2 p d)
(prt-4play-data play2 p2)
(clear-4play-data play2 p d)
(clear-4play-data play2 p2)

minoru yamaguchi



minoru yamaguchi

unread,
May 8, 2021, 10:21:04 PM5/8/21
to extemp...@googlegroups.com
Hi George, 

This is last part ....

Part 5      

;; general usage, to figure out these funcitons
;;   get variable value and assign it to variable in any function
;;   because these 2 funcions do macro expansion in target S-expression,
;;   so, these can get from and assign it to variable. 

(let ((x 555)
      (y 'a)
      (z '(a b c)))
  (get-4play-data anonym x y z)
  (list x y z))
; returns (555 a (a b c))

(get 'anonym 'x) ;(555)
(get 'anonym 'y) ;(a)
(get 'anonym 'z) ;(a)

(rev-4play-data anonym x y z)
(dup-4play-data anonym x y z)

(let ((x 10)
      (y 20)
      (z 30))
  (list x y z))
;returns (10 20 30)

(let ((x 10)
      (y 20)
      (z 30))
  (assign-4play-data anonym x y z)
  (list x y z))
;; returns (555 a (a b c))

(clear-4play-data anonym x y z)
(dup-4play-data anonym x y z)

minoru yamaguchi



Minoru

unread,
May 9, 2021, 1:49:43 AM5/9/21
to Extempore
correction on Part 5

(get 'anonym 'z) ;(a)     ----->>  (get 'anonym 'z) ;(a b c)

2021年5月9日日曜日 11:21:04 UTC+9 Minoru:

geor...@bigpond.net.au

unread,
May 9, 2021, 4:42:28 AM5/9/21
to Extempore
Minoru
You have gone right back to my original posting of Dec 11, 2020.
And you have effectively written a tutorial on the subject.
Of course it will take me some time to digest it all.
I'm sure that the material in this thread would be of value to others like me who are novices.
Maybe it should be written up and included in the extempore docs.
I'll let you know how I get on.
Thank you Minoru.
Thanks to others who have contributed.
Regards
George

Ben Swift

unread,
May 9, 2021, 4:47:30 AM5/9/21
to extemp...@googlegroups.com

> Maybe it should be written up and included in the extempore docs.

Sure, I’m open to the idea :)

Ben

Minoru

unread,
May 10, 2021, 7:59:35 AM5/10/21
to Extempore
Hi George,

I think you already noticed what I'm going to suggest here, maybe ..........
This is one of the powerful abilities of Extempore.

;; notes

;; Actually it's possible to play back the recorded data directly after recording
;; without stopping the playing function. 
;; And recording again without any stop, too.
;; You can record then play back then record new data then play back again
;; and so on ... without cease !


(define play1
  (lambda (beat-n)
    (let ((p (random '(60 60 63 67 70 72 75 79 82)))
          (v 70)
          (d (random '(1 1/2 1/2 1/4))))

   ;; (get-4play-data play1 p d) ; 1 recording data
   ;; (assign-4play-data play1 p d) ; 2 comment out when recording

      (play-note (*metro* beat-n) fmsynth p v (*metro* 'dur d) .24 .5)
      (callback (*metro* (+ beat-n (* .5 d))) 'play1 (+ beat-n d)))))

(play1 (*metro* 'get-beat)) ; just once !

;;   When you want to record the random data,
;;   do uncomment line 1 : (get-4play-data play1 p d)
;;   then re-evaluate this function definition (define play1 ....)
;;   ok now it is beginning to record the data : p, d  .

;; And when you want to stop recording,
;; comment out the line 1 : (get-4play-data play1 p d)
;; then re-evaluate this function,
;; now this play1 is playing the random data without recording. 
;; Then evaluate below 2 lines...
(rev-4play-data play1 p d) ; makes original order
(dup-4play-data play1 p d) ; duplicates the data

;; When you want to play or play back this recorded data,
;; do uncomment the line 2 : (assign-4play-data play1 p d)
;; then re-evaluate this play1 function,
;; now this play1 is playing back or playing the recorded data.

;; Anytime you can change the mode of recording and play-back ceaselessly like above,
;; of course, as many times as you want.


;; You can edit the recoeded data as you want, too.
;; Because you can get the data which play1 function made and (get-4play-data ..) recorded.
(get 'play1 'p)
(put 'play1 'p your-edited-data-list)
;; the original data was changed but not ready to be played yet,
;; it's necessary to do
(dup-4play-data play1 p d)
;; before uncomment the line 2 : (assign-4play-data play1 p d) .

;; OR
(get 'play1-dup 'p)  ; 1st argument form is anyname-dup
;; this scheme line gets the data used for playing back,
;; and this data was already made by (dup-4play-data play1 p d) .
;; Then do like this ...
(put 'play1-dup 'p your-edited-data-list)
;; this data is directly played via (assign-4play-data ....) without doing
(dup-4play-data play1 p d)
;; this time, the original recorded data is not changed at all,
;; so you can refer to the original one anytime.


;; If you do as follows, the recorded data is cleared,
;; then the next recording gets all new one.
;; On the other hand, You could add the new recording data to the old one
;; without this process.
(clear-4play-data play1 p d)

;; the end 
(define play1 (lambda ()))


2021年5月9日日曜日 17:47:30 UTC+9 ben:

George Wright

unread,
May 11, 2021, 6:00:01 PM5/11/21
to extemp...@googlegroups.com
Thanks Minoru
You are well ahead of me but I’ll get there eventually.

I want to go back to the “Connecting extempore to DAW “ which I have working OK now.
Following Duncan’s13/12/2020  suggestion (attached) I tried my luck with Ardour6. ………..
I can make the connection but I can’t simultaneously send separate midi to separate channels loaded with different instruments.
All signals go to all instruments.
I think it has something to do with Ardour Patchbay.  https://manual.ardour.org/signal-routing/Patchbay/
I’m hoping Duncan has a simple solution to this.

I had the same experience with GarageBand. A search of GarageBand help sites seems to suggest that sending separate midi signals to different instruments simultaneously is not possible. But I’m not sure about that.
Regards
George

minoru yamaguchi

unread,
May 12, 2021, 10:14:41 PM5/12/21
to extemp...@googlegroups.com
George


>I can make the connection but I can’t simultaneously send separate midi to separate >channels loaded with different instruments.
>All signals go to all instruments.

>I had the same experience with GarageBand. A search of GarageBand help sites seems to >suggest that sending separate midi signals to different instruments simultaneously is not >possible. But I’m not sure about that.

I had the same experiences as above, too, though I've never tried Ardour6, but and more, that is, Logic Pro X and Cubase (bandle) besides GarageBand ....
It made me get KONTAKT 6 Player, in order to avoid this problem.


2021年5月12日(水) 7:00 George Wright <geor...@bigpond.net.au>:
--
You received this message because you are subscribed to the Google Groups "Extempore" group.
To unsubscribe from this group and stop receiving emails from it, send an email to extemporelan...@googlegroups.com.


--
Minoru Yamaguchi

Duncan McGreggor

unread,
May 13, 2021, 12:20:00 AM5/13/21
to extemp...@googlegroups.com
Hey George ... let's see, it's been a while since I used Ardour ... (wow, it's really slow with the ol' VST scan; painfully slow)

Okay, set up a new song with MIDI tracks like I mentioned before (I had to read my own instructions again). I'm not sure if Ardour let's you set individual MIDI channels in a given track? However, the VST plugins I have did let me do that. Here's a screenshot of what I just did:
Screenshot 2021-05-12 at 11.10.49 PM.png
Each track has its own instance of Analog Lab. I double-clicked on the instrument name for each to open the VST plugin, and in the plugin's setting for each, set the MIDI channels (to 1 and 2, respectively). I then did a quick test with Extempore patterns writing a different set of notes to each channel, and got the expected results (the generated audio is visible in each track's meter readout).

Hope this helps?

d

--
You received this message because you are subscribed to the Google Groups "Extempore" group.
To unsubscribe from this group and stop receiving emails from it, send an email to extemporelan...@googlegroups.com.

Minoru

unread,
May 19, 2021, 8:17:28 AM5/19/21
to Extempore
Hi Geoge and all,

Here are some codes to get and store the value of variables in a playing
function that makes random value as pitch, duration etc while playing .... 

This time, it writes the value to a file, and of course,
it assigns the data from the file to the variables in any playing function.

Now it's much easier than before to manipulate them while playing the music.

You could edit the data of these files, because their form is very simple,
just a list, like (value1 value2 ..) (value1 value2 .....).....
So it's possible to write all data by your self without recording,
then any play function can play music with this data from a file, too.


;; This function sets file port variables and file,
;; and put path-file name in a property list of this file port variable.
;; (fl-set *fport-out1* *fport-in1* "/any..path/fname"  )
;; 
(define-macro (fl-set f-out-port f-in-port f-path-name)
  `(begin
     (define ,f-out-port 'closed) ; file port var as gloval variable
     (put ,f-out-port 'fname (quote ,f-path-name))
     (define ,f-in-port 'closed)
     (put ,f-in-port 'fname (quote ,f-path-name))))


;; file open function
;; arguments are  <out> or <in>、<file port var name defined in fl-set> 
;; (fl-open out *fport-out1*)
;; or
;; (fl-open in *fport-in1*)
;; 
(define-macro (fl-open out-or-in f-port-var)
  `(begin
     (set! ,f-port-var (,(if (eq? out-or-in 'out) 'open-output-file 'open-input-file)
(get ,f-port-var 'fname)))
     (println ,(if (eq? out-or-in 'out) ''open-out ''open-in))))


;; file close function
;; arguments are  <out> or <in>、<file port var name defined in fl-set> 
;; (fl-close out *fport-out1*)
;; or
;; (fl-close in *fport-in1*)
;; 
(define-macro (fl-close out-or-in f-port-var)
  `(begin
     (if (eq? ,f-port-var 'closed)
'already-closed-!
(begin
  (,(if (eq? out-or-in 'out) 'close-output-port 'close-input-port) ,f-port-var)
  (set! ,f-port-var 'closed)
  (println ,(if (eq? out-or-in 'out) ''close-out ''close-in))))))

 
;; This function gets data in a function then writes it to the file
;; while the target file is open, not closed,
;; if closed, it does nothing.
;; (f-get-4play-data *fport-out1* p v d ...)
;;
(define f-get-4play-data
  (lambda (f-port-var . args)
    (if (not (eq? f-port-var 'closed))
(let ((a (gensym)))
 (let ((got-data (map (lambda (a) a)
      args)))
   (write got-data f-port-var))))))


;; This function reads data from a file and assigns them to the variables in a function,
;; while the target file is open, not closed.
;; When this gets a end of file, close the file and stop to read,
;; then do nothing while the data file is closed.
;; This function begins to read the file again whenever the file is opened by (fl-open .....)
;; (f-assign-4play-data *fport-in1* p v d ...)
;; 
(define-macro (f-assign-4play-data f-port-var . args) ; arguments are *fport-in1* p v d etc
  (let ((a (gensym))) 
    `(if (not (eq? ,f-port-var 'closed))
(let ((s-exp-data (read ,f-port-var)))
  (if (eof-object? s-exp-data)
      (begin
(close-input-port ,f-port-var)
(set! ,f-port-var 'closed)
(println "file end and close-in ..."))
      (map (lambda (,a)
     (eval (list 'set! ,a '(car s-exp-data))) ; corrected, 2020-04-02 by minoru 
     (set! s-exp-data (cdr s-exp-data)))
   (quote ,args)))))))


;;;;;  playing music, recoding and playing(back) the data   ;;;;;
(begin
  (sys:load "libs/core/instruments.xtm")
  (sys:load "libs/core/pc_ivl.xtm")
  (sys:load "libs/core/audio_dsp.xtm" )
  )
(make-instrument fmsynth fmsynth)
(bind-func dsp:DSP
  (lambda (in time chan dat)
    (fmsynth in time chan dat)))
(dsp:set! dsp)

;; just simple playing function with random data
(define play1
  (lambda (beat-n)
    (let ((p (+ 0 (random '(60 64 67 72 76)))) ; change 0 -> 12 or 24 after recording data
          (v 70)
          (d (random '(1 1/2 1/2 1/4))))

      (f-get-4play-data *fport-out2* p d)   ; 1 to file
      (f-assign-4play-data *fport-in2* p d) ; 2 from file

      (play-note (*metro* beat-n) fmsynth p v (*metro* 'dur d) .24 .5)
      (callback (*metro* (+ beat-n (* .5 d))) 'play1 (+ beat-n d)))))


;; You have to evaluate this before play1 involving (f-get- ....) and (f-assign- ....) runs.
(fl-set *fport-out2* *fport-in2* "/.../save-file2.txt");<-Use a real file path/name!

;; start playing now !
(play1 (*metro* 'get-beat))

;; it's just playing ......

;; evaluate this to begin recording when you like
(fl-open out *fport-out2*)

;; evaluate this to stop recording at anytime
(fl-close out *fport-out2*)

;; don't stop the music !
;; chnage the above (p (+ 0 .....)) to (p (+ 12), then re-evaluate it.
;; you hear the higher sounds after this changing value.

;; then you can hear the lower sounds when evaluate the below line ..
;; because play1 uses p,d data from the file now
(fl-open in *fport-in2*)


;; when you evaluate this, reading data from the file stops with priting "close-in",
;; then you hear the higher sounds because of (p (+ 12 ...)), that is, playing
;; random data starts again, not data from the file.
(fl-close in *fport-in2*)

;; when it gets end of file before you do above (fl-close in ....)
;; the same results as above comes with printing "file end and closed ..."

;; and anytime you do above (fl-open in *fport-in2*),
;; you hear the lower sounds because of the file data ...

;; While the file is closed, e.g., (fl-close in ...) or "file end and closed",
;; (fl-open out *fport-out2*) makes it's new recording start again,
;; You can do this as many times as you want.

;; end
(define play1 (lambda ()))

;; you can write or edit the file directly, too, of course !!
;; data file is (value1 value2 ..) (value1 value2 .....) .... just simple!
;; It reads one list at every time.


;;;;;;;;;;;;; general understanding

;; you should do this before the target function involving (f-get ...) (f-assign ....) runs.
(fl-set *fport-out1* *fport-in1* "/..../save-file.txt");<-Use a real file path/name!

;; run this, 
(let ((p 0)    ; change value
      (v 40)   ; change value
      (d 1/4)) ; change value
  (f-get-4play-data *fport-out1* p v d)
  (f-assign-4play-data *fport-in1* p v d)
  (list p v d)))

;; evaluate 
(fl-open out *fport-out1*)
;; then evaluate above (let ..) 2 or 3 times as you like with changing value every time.
;; then evaluate below ...
(fl-close out *fport-out1*)

;; then evaluate the (let ...) without changing value
;; so you see the same result at every evaluating.

;; then evaluate below, then re-evaluate above (let ...) without changing value,
;; so you see a defferent result because of the data from file.
;; When it gets end of file, re-evaluating (let ...) brings the results that is
;; written in this (let ...).
(fl-open in *fport-in1*)

;; you can stop reading the data from the file at anytime.
(fl-close in *fport-in1*)


Hope this helps.

2021年5月13日木曜日 13:20:00 UTC+9 dun...@mcgreg.gr:

Minoru

unread,
May 29, 2021, 2:46:19 AM5/29/21
to Extempore
Hi all, 

I added Fast Forwarding function which can set the start - end place
of the recorded data on the file.

Some changes on the others, too .....

;; This function sets two file port variables and a file,
;; these file port variables are defined as gloval variables,
;; and put the path-file name in a property list of this file port variable.
;; Old version used a property list of value of this file port variable, 
;; a token, like as #<PORT0x1153a7240>, but now not value but gloval variable name,
;; like as '*fport-in1* etc .... (put '*fport-in1* 'fname "/any..path/fname")
;; 
;; usage: (fl-set *fport-out1* *fport-in1* "/any..path/fname"  )
;; 
(define-macro (fl-set f-out-port f-in-port f-path-name)
  `(begin
     (define ,f-out-port 'closed) ; file port var as gloval variable
     (put (quote ,f-out-port) 'fname ,f-path-name)
     (define ,f-in-port 'closed)
     (put (quote ,f-in-port) 'fname ,f-path-name)
     (put (quote ,f-in-port) 'f-count 0)))


;; file open function
;; arguments are  <out> or <in>、<file port var name defined in fl-set> 
;; usage: (fl-open out *fport-out1*)
;;        or
;;        (fl-open in *fport-in1*)
;; 
(define-macro (fl-open out-or-in f-port-var)
  `(begin
     (fl-close ,out-or-in ,f-port-var)
     (set! ,f-port-var (,(if (eq? out-or-in 'out) 'open-output-file 'open-input-file)
(get (quote ,f-port-var) 'fname)))
     (println ,(if (eq? out-or-in 'out) ''open-out ''open-in))
     (put (quote ,f-port-var) 'f-count 0)
     (put (quote ,f-port-var) 'end-n 0)))


;; file close function
;; arguments are  <out> or <in>、<file port var name defined in fl-set> 
;; usage: (fl-close out *fport-out1*)
;;        or
;;        (fl-close in *fport-in1*)
;; 
(define-macro (fl-close out-or-in f-port-var)
  `(begin
     (if (eq? ,f-port-var 'closed)
'already-closed-!
(begin
  (,(if (eq? out-or-in 'out) 'close-output-port 'close-input-port) ,f-port-var)
  (set! ,f-port-var 'closed)
  (println ,(if (eq? out-or-in 'out) ''close-out ''close-in))))))

 
;; This function gets data in a function that including this function,
;; then writes it to the file while the target file is open,
;; not closed, thas is, after (fl-open out .....)
;; if closed by (fl-close out ...), this does nothing.
;; 
;; usage: (f-get-4play-data *fport-out1* p v d ...)
;;
(define f-get-4play-data
  (lambda (f-port-var . args)
    (if (not (eq? f-port-var 'closed))
(let ((a (gensym)))
 (let ((got-data (map (lambda (a) a)
      args)))
   (write got-data f-port-var))))))


;; This function reads data from a file and assigns them to the variables
;; in a function involving this funtion while the target file is open, not closed.
;; When this gets a end of file, close the file and stop to read,
;; then do nothing while the data file is closed.
;; This function begins to read the file again whenever the file
;; is opened by (fl-open .....) or (fl-opne-ff ......)
;; 
;; usage: (f-assign-4play-data *fport-in1* p v d ...)
;; 
(define-macro (f-assign-4play-data f-port-var . args)
  (let ((a (gensym))) 
    `(if (not (eq? ,f-port-var 'closed))
(let ((n (+ 1 (get (quote ,f-port-var) 'f-count)))
      (end-num (get (quote ,f-port-var) 'end-n))
      (s-exp-data (read ,f-port-var)))
  (cond ((or (and (> end-num 0)
  (> n end-num))
     (eof-object? s-exp-data))
 (fl-close in ,f-port-var)
 (put (quote ,f-port-var) 'end-n 0)
 (put (quote ,f-port-var) 'f-count 0)
 (if (eof-object? s-exp-data)
     (println 'file 'end)
     (println 'file 'data 'exceed end-num)))
(else
 (print n)(print ":")(print s-exp-data)(print ", ")
 (put (quote ,f-port-var) 'f-count n)
 (map (lambda (,a)
(eval (list 'set! ,a '(car s-exp-data)))
(set! s-exp-data (cdr s-exp-data)))
      (quote ,args))))))))


;; This fast forwards the file reading,
;; and an optional argument sets the end position at any place, too.
;; 
;; usage:
;; (fl-open-ff *fport-in1* 2) reads 2 list, so you get the data from 3rd to the last.
;; (fl-open-ff *fport-in1* 1 4) read 1 list, and sets the 4th data as the last one,
;;      so you get the data from 2nd to 4th.
;; (fl-open-ff *fport-in1* 0 4) you get the data from 1st to 4th.
;; 
;; It's possible to run this again befor the setting condition is over, that is,
;; while using the data on the condition that preceding another this function set,
;; or without closing the file, (fl-close in *fport-in2*),
;; you can run this again and again at any time you like. 
;; 
(define-macro (fl-open-ff f-port-var ffn . end-targ-n)
  `(begin
     (fl-close in ,f-port-var)
     (set! ,f-port-var (open-input-file (get (quote ,f-port-var) 'fname)))
     (put (quote ,f-port-var) 'f-count 0)
     (if (null? (quote ,end-targ-n))
(put (quote ,f-port-var) 'end-n 0)
(put (quote ,f-port-var) 'end-n (car (quote ,end-targ-n))))
     (if (not (= 0 ,ffn))
(let loop ((n 1) (s-exp-data (read ,f-port-var)))
  (if (or (>= n ,ffn) (eof-object? s-exp-data))
      (cond ((eof-object? s-exp-data)
     (fl-close in ,f-port-var)
     (put (quote ,f-port-var) 'f-count 0)
     (put (quote ,f-port-var) 'end-n 0)
     (println "FF over, file end ..."))
    (else
     (put (quote ,f-port-var) 'f-count n)))
      (loop (+ n 1) (read ,f-port-var)))))))



;;;;;  example of playing music, recoding and playing(back) the file data   ;;;;;

(begin
  (sys:load "libs/core/instruments.xtm")
  (sys:load "libs/core/pc_ivl.xtm")
  (sys:load "libs/core/audio_dsp.xtm" )
  )
(make-instrument fmsynth fmsynth)
(bind-func dsp:DSP
  (lambda (in time chan dat)
    (fmsynth in time chan dat)))
(dsp:set! dsp)

;; just simple playing function with random data
(define play1
  (lambda (beat-n)
    (let ((p (+ 0 (random '(60 64 67 72 76)))) ; change 0 -> 12 or 24 after recording data
          (v 70)
          (d (random '(1 1/2 1/2 1/4))))

      (f-get-4play-data *fport-out2* p d)   ; just add these 2 lines in your ordinary 
      (f-assign-4play-data *fport-in2* p d) ; playing function.

      (play-note (*metro* beat-n) fmsynth p v (*metro* 'dur d) .24 .5)
      (callback (*metro* (+ beat-n (* .5 d))) 'play1 (+ beat-n d)))))


;; You have to evaluate this before play1 involving (f-get- ....) and (f-assign- ....) runs.
(fl-set *fport-out2* *fport-in2* "/.../save-file2.txt");<-Use a real file path/name !!!

;; start playing now !
(play1 (*metro* 'get-beat))

;; it's just playing ......

;; evaluate this to begin recording when you like
(fl-open out *fport-out2*)

;; evaluate this to stop recording at anytime
(fl-close out *fport-out2*)

;; don't stop the music !
;; chnage the above (p (+ 0 .....)) to (p (+ 12), then re-evaluate it.
;; you hear the higher sounds after this change.

;; then you can hear the lower sounds when evaluate the below line ..
;; because play1 uses p,d data from the file now,
;; and you see the number and data from the file in the shell window.
(fl-open in *fport-in2*)


;; when you evaluate this, reading data from the file stops with printing "close-in",
;; then you hear the higher sounds because of (p (+ 12 ...)), that is, playing
;; random data starts again, not data from the file.
(fl-close in *fport-in2*)

;; when it gets end of file before you do above (fl-close in ....)
;; the same results as above comes with printing "file end and closed ..."

;; and anytime you do above (fl-open in *fport-in2*),
;; you hear the lower sounds because of the file data ...
;; and you can rewind it whenever you do this (fl-open in *fport-in2*). 

;; then you evaluate this, play1 begins to play the data from 11th to the last
;; on the file, you can do this at any time. It's possible to do this again
;; without waiting the end of file.
(fl-open-ff *fport-in2* 10)

;; and by next code, play1 plays from 11th to 20th, then stops to reading,
;; then play1 plays random data again as (define play1 ....)
;; and you can re-evaluate this code while the preceding this code is running,
;; so you can do this again while paying data is between 11th - 20th,
;; then play1 plays from 11th again, or with different argument values that
;; makes play1 play the data of another place on the same file,
;; at anytime you like, as many as you like.
(fl-open-ff *fport-in2* 10 20)

;; While the file is closed, e.g., (fl-close in ...) or "file end and closed",
;; (fl-open out *fport-out2*) makes it's new recording start again,
;; You can do this as many times as you want.

;; end
(define play1 (lambda ()))

;; You can write or edit the file directly, too, of course !!
;; this data file is (value1 value2 ..) (value1 value2 .....) .... just simple!
;; It reads one list at every time.

Hope this helpls.

;; p.s.
;; I tried above functions on a file consists of 7980 lists, sum of duration is 4480 beat,
;; it meant the data to play for 37.3 min by 120bpm. It's enough long.
;; This code (fl-open-ff *fport* 7970) was evaluated many times befor it's over,
;; and it did that FF without any delay or stagnation.


2021年5月19日水曜日 21:17:28 UTC+9 Minoru:

geor...@bigpond.net.au

unread,
May 29, 2021, 3:39:25 AM5/29/21
to Extempore
Minoru
Hadn't tried your older version but did just now try the new.
Thanks for the "usage" comments - they will be very helpful.
However when I got to the :

;; start playing now !
(play1 (*metro* 'get-beat))

;; it's just playing ......

;; evaluate this to begin recording when you like
(fl-open out *fport-out2*)

The playing stopped and I got this error:

open-out
function(write): argument 2 must be: output_port
argument values: ((76 1/2) #f) #<PROC write>
Trace: f-get-4play-data <- play1

I'm sure you will understand this message better than I do.

Regards
George

Minoru

unread,
May 29, 2021, 4:02:59 AM5/29/21
to Extempore
George

Thanks for your quick trial.
Please tell me ....

1: Did you write the correct path-file name ?
(fl-set *fport-out2* *fport-in2* "/.../save-file2.txt") ; <-Use a real file path/name !!!

2: Are play1 and included 2 lines just same as my example or something changed ?

Regards

2021年5月29日土曜日 16:39:25 UTC+9 geor...@bigpond.net.au:

George Wright

unread,
May 29, 2021, 4:21:43 AM5/29/21
to extemp...@googlegroups.com
Minoru
play1 and path name both look OK to me.

;; just simple playing function with random data
(define play1
(lambda (beat-n)
(let ((p (+ 0 (random '(60 64 67 72 76)))) ; change 0 -> 12 or 24 after recording data
(v 70)
(d (random '(1 1/2 1/2 1/4))))
(f-get-4play-data *fport-out2* p d) ; just add these 2 lines in your ordinary
(f-assign-4play-data *fport-in2* p d) ; playing function.
(play-note (*metro* beat-n) fmsynth p v (*metro* 'dur d) .24 .5)
(callback (*metro* (+ beat-n (* .5 d))) 'play1 (+ beat-n d)))))


;; You have to evaluate this before play1 involving (f-get- ....) and (f-assign- ....) runs.
(fl-set *fport-out2* *fport-in2* "Users/georgewright/extempore/Extempore_SavedStuff/MIDI_STUFF/minoru_file1.txt");<-Use a real file path/name !!!

;; start playing now !
(play1 (*metro* 'get-beat))

;; it's just playing ......

;; evaluate this to begin recording when you like
(fl-open out *fport-out2*)

Regards
George

George Wright


Minoru

unread,
May 29, 2021, 4:29:32 AM5/29/21
to Extempore
George

>(fl-set *fport-out2* *fport-in2* "Users/georgewright/extempore/Extempore_SavedStuff/MIDI_STUFF/minoru_file1.txt");<-Use a real file path/name !!!

I think that the correct path-file name is not "Users/..."  but   "/Users/...."

Regards


2021年5月29日土曜日 17:21:43 UTC+9 geor...@bigpond.net.au:

Minoru

unread,
May 29, 2021, 4:36:12 AM5/29/21
to Extempore
George

I tried a file path like "Users/ ..../" then got the same error messages as you did.

open-out
function(write): argument 2 must be: output_port
argument values: ((76 1/2) #f) #<PROC write>
Trace: f-get-4play-data <- play1

Regards

2021年5月29日土曜日 17:29:32 UTC+9 Minoru:

George Wright

unread,
May 29, 2021, 4:50:24 AM5/29/21
to extemp...@googlegroups.com
You are correct Minoru. “/Users/ ………"
Working perfectly now.
Have tried the replay of lower pitch mixed with octave higher.
Works perfectly.
You are a marvel Minoru!
Congratulations

George

George Wright



-- 
You received this message because you are subscribed to a topic in the Google Groups "Extempore" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/extemporelang/9cQqmflEdpY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to extemporelan...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/extemporelang/0946bb3d-5179-4813-bbdf-bccd2757712dn%40googlegroups.com.

Minoru

unread,
May 29, 2021, 5:52:53 AM5/29/21
to Extempore
George

It's my pleasure, and I'm glad to know that your trial worked well !
Thanks!

2021年5月29日土曜日 17:50:24 UTC+9 geor...@bigpond.net.au:

George Wright

unread,
May 29, 2021, 6:02:26 PM5/29/21
to extemp...@googlegroups.com
Minoru
I wonder if I made a another instrument and modified  dsp for it, I could make a another play function.
Then I could replay the recorded data on a different instrument using play2 or play3 ...
It might sound interesting to have an initial pattern repeatedly recurring against a background of randomness.
Do you think this is worth a try?

Just one side issue Minoru.
I am using Visual Studio Code.
I notice that Code is quite conscientious about checking for bracket balance
even within comments. So if there is an unbalanced ( within a commented-out section
some unwanted indentation happens and continues (in this case) right to the end of the file >

;; don't stop the music !
;; chnage the above (p (+ 0 .....)) to (p (+ 12), then re-evaluate it.
;; you hear the higher sounds after this change.
;; then you can hear the lower sounds when evaluate the below line ..
;; because play1 uses p,d data from the file now,
;; and you see the number and data from the file in the shell window.
(fl-open in *fport-in2*)

Balancing the brackets in this line >
;; chnage the above (p (+ 0 .....)) to (p (+ 12 ….)), then re-evaluate it.
and then saving, will fix it.
I’ve noticed the same phenomenon in some of the extempore examples.
I’ve no idea if this is a issue in other editors.
Maybe Ben knows how to fix the Code extempore extension or whatever … that’s all beyond my abilities.

Regards
George

George Wright


On 29 May 2021, at 7:52 pm, Minoru <mils...@gmail.com> wrote:

George

Minoru

unread,
May 30, 2021, 2:11:05 AM5/30/21
to Extempore
Hi, George

I think so, too, then I'd like to know the fruits... 

I wrote this code to avoid writing file-input-output parts every time in every function that needs it. This is one of my personal reasons and I hope it's useful for someone.
Just inserting 2 lines with variables whose value you need, you can use some playing functions without writing any file-input-output processes, so it's easy to do that.
Go ahead, please.

About editor, I use emacs installed "smartparens.el" and no problem for unbalanced parentheses in comments.
But sorry for "(p (+ 12) ",  lack of ")",  it's my mistake, and emacs complained nothing about it in comments, I'm not sure if it's good or bad ..... but when I look at it carefully now I notice there no highlighted right paren for "(p" , so the fact's that emacs said something about it so modestly.

Regards

2021年5月30日日曜日 7:02:26 UTC+9 geor...@bigpond.net.au:

Minoru

unread,
May 30, 2021, 2:59:29 AM5/30/21
to Extempore
Hi, George

Just now I confirmed the same phenomenon as you showed, on VScode with extempore extension.
I inserted "enter" in front of the same "(fl-open in *fport-in2*)", it resulted unwanted indentation.

On the other hand, the same "enter" insertion at the same position made no new unwanted indentation, just new line, on emacs.

Regards

2021年5月30日日曜日 15:11:05 UTC+9 Minoru:

Minoru

unread,
Jun 2, 2021, 4:41:33 AM6/2/21
to Extempore
Hi, George and all,

This time, f-get-4play-data prints the counted number while writing
the data to file, in order to memorize the place when you find the sound,
phrase or rhythm you like.

On the other hand, f-get-4play-data, f-assign-4play-data added an argument
for printing on-off.

And 2 tiny tools.

Some changes on the others, too .....


;; This function sets two file port variables and a file,
;; these file port variables are defined as gloval variables,
;; and put the path-file name in a property list of this file port variable.
;; Old version used a property list of value of this file port variable, 
;; a token, like as #<PORT0x1153a7240>, but now not value but gloval variable name,
;; like as '*fport-in1* etc .... (put '*fport-in1* 'fname "/any..path/fname")
;; 
;; usage: (fl-set *fport-out1* *fport-in1* "/any..path/fname"  )
;; 
(define-macro (fl-set f-out-port f-in-port f-path-name)
  `(begin
     (define ,f-out-port 'closed) ; file port var as gloval variable
     (put (quote ,f-out-port) 'fname ,f-path-name)
     (define ,f-in-port 'closed)
     (put (quote ,f-in-port) 'fname ,f-path-name)
     (fl-init (quote ,f-in-port))
     ))


;; initialize f-count, end-n, called by some functions
;; 
(define fl-init
  (lambda (f-port-var)
    (put f-port-var 'f-count 0)
    (put f-port-var 'end-n 0)))


;; file open function
;; arguments are  <out> or <in>、<file port var name defined in fl-set> 
;; usage: (fl-open out *fport-out1*)
;;        or
;;        (fl-open in *fport-in1*)
;; 
(define-macro (fl-open out-or-in f-port-var)
  `(begin
     (fl-close ,out-or-in ,f-port-var)
     (set! ,f-port-var (,(if (eq? out-or-in 'out) 'open-output-file 'open-input-file)
(get (quote ,f-port-var) 'fname)))
     (println ,(if (eq? out-or-in 'out) ''open-out ''open-in))
     (fl-init (quote ,f-port-var))))


;; file close function
;; arguments are  <out> or <in>、<file port var name defined in fl-set> 
;; usage: (fl-close out *fport-out1*)
;;        or
;;        (fl-close in *fport-in1*)
;; 
(define-macro (fl-close out-or-in f-port-var)
  `(begin
     (if (eq? ,f-port-var 'closed)
'already-closed-!
(begin
  (,(if (eq? out-or-in 'out) 'close-output-port 'close-input-port) ,f-port-var)
  (set! ,f-port-var 'closed)
  (println ,(if (eq? out-or-in 'out) ''close-out ''close-in))
  (fl-init (quote ,f-port-var))))))


;; This function gets data in a function that including this function,
;; then writes it to the file while the target file is open,
;; not closed, thas is, after (fl-open out .....)
;; if closed by (fl-close out ...), this does nothing.
;; And this prints out the count number of writing data in shell window while working.
;;
;; 2nd argument is boolean, #t or #f for printing on/off
;;
;; usage:
;; (f-get-4play-data *fport-out1* #t p v d p2 v2...) 2nd arg #t to print the counting number,
;;   or
;; (f-get-4play-data *fport-out1* #f p v d p2 v2...) 2nd arg #f, no print
;;        
(define-macro (f-get-4play-data f-port-var prt-bool . args)
  (let ((a (gensym)))
    `(if (not (eq? ,f-port-var 'closed))
(let ((n (+ 1 (get (quote ,f-port-var) 'f-count)))
      (got-data (map (lambda (,a)
(eval ,a))
     (quote ,args))))
  (if ,prt-bool
      (begin (print n) (print ", ")))
  (put (quote ,f-port-var) 'f-count n)
  (write got-data ,f-port-var)))))


;; This function reads data from a file and assigns them to the variables
;; in a function involving this funtion, printing the count number and it's
;; data in the shell window while the target file is open, not closed.
;; When this gets a end of file, close the file and stop to read,
;; then do nothing while the data file is closed.
;; This function begins to read the file again whenever the file
;; is opened by (fl-open .....) or (fl-opne-ff ......)
;;
;; 2nd argument is boolean, #t or #f for printing on/off.
;; 
;; usage:
;; (f-assign-4play-data *fport-in1* #t p v d p2 v2 ...)  prints the data in the shell window.
;;   or
;; (f-assign-4play-data *fport-in1* #f p v d p2 v2 ...)  no print, because of 2nd arg.
;;        
(define-macro (f-assign-4play-data f-port-var prt-bool . args)
  (let ((a (gensym))) 
    `(if (not (eq? ,f-port-var 'closed))
(let ((n (+ 1 (get (quote ,f-port-var) 'f-count)))
      (end-num (get (quote ,f-port-var) 'end-n))
      (s-exp-data (read ,f-port-var)))
  (cond ((or (and (> end-num 0)
  (> n end-num))
     (eof-object? s-exp-data))
 (fl-close in ,f-port-var)
 (if (eof-object? s-exp-data)
     (println 'file 'end)
     (println 'file 'data 'exceed end-num)))
(else
 (if ,prt-bool
     (begin (print n) (print ":") (print s-exp-data)(print ", ")))
 (put (quote ,f-port-var) 'f-count n)
 (map (lambda (,a)
(eval (list 'set! ,a '(car s-exp-data))) ; corrected, 2020-04-02 by minoru 
(set! s-exp-data (cdr s-exp-data)))
      (quote ,args))))))))


;; This fast forwards the file reading,
;; and optional argument sets the end position at any place, too.
;; 
;; usage:
;; (fl-open-ff *fport-in1* 2) reads 2 list, so you get the data from 3rd to the last.
;; (fl-open-ff *fport-in1* 1 4) read 1 list, and sets the 4th data as the last one,
;;      so you get the data from 2nd to 4th.
;; (fl-open-ff *fport-in1* 0 4) you get the data from 1st to 4th.
;; 
;; It's possible to run this again befor the setting condition is over, that is,
;; while using the data on the condition that preceding another this function set,
;; or without closing the file, (fl-close in *fport-in2*),
;; you can run this again and again at any time you like. 
;; 
(define-macro (fl-open-ff f-port-var ffn . end-targ-n)
  `(begin
     (fl-close in ,f-port-var)
     (set! ,f-port-var (open-input-file (get (quote ,f-port-var) 'fname)))
     (if (null? (quote ,end-targ-n))
(put (quote ,f-port-var) 'end-n 0)
(put (quote ,f-port-var) 'end-n (car (quote ,end-targ-n))))
     (if (not (= 0 ,ffn))
(let loop ((n 1) (s-exp-data (read ,f-port-var)))
  (if (or (>= n ,ffn) (eof-object? s-exp-data))
      (cond ((eof-object? s-exp-data)
     (fl-close in ,f-port-var)
     (println "FF over, file end ..."))
    (else
     (put (quote ,f-port-var) 'f-count n)))
      (loop (+ n 1) (read ,f-port-var)))))))

;;;;;  example of playing music, recoding and playing(back) the file data   ;;;;;

(begin
  (sys:load "libs/core/instruments.xtm")
  (sys:load "libs/core/pc_ivl.xtm")
  (sys:load "libs/core/audio_dsp.xtm" )
  )
(make-instrument fmsynth fmsynth)
(bind-func dsp:DSP
  (lambda (in time chan dat)
    (fmsynth in time chan dat)))
(dsp:set! dsp)

;; just simple playing function with random data

(define play1
  (lambda (beat-n)
    (let ((p (+ 0 (random '(60 64 67)))) ; change 0 -> 12 or 24 after recording data
          (v 70)
          (d (random '(1 1/2 1/2 1/4))))

         ;; just add these 2 lines in your ordinary playing function,
         ;; and add variables as many as you need, p2 v2 d2 etc ...
      (f-get-4play-data *fport-out2* #t p d)   ;  to file, print on
      (f-assign-4play-data *fport-in2* #t p d) ;  from file, print on

      (play-note (*metro* beat-n) fmsynth p v (*metro* 'dur d) .24 .5)
      (callback (*metro* (+ beat-n (* .5 d))) 'play1 (+ beat-n d)))))


;; You have to evaluate this before play1 involving (f-get- ....) and (f-assign- ....) runs.
(fl-set *fport-out2* *fport-in2* "/.../save-file2.txt");<-Use a real file path/name !!!

;; start playing now !
(play1 (*metro* 'get-beat))

;; it's just playing ......

;; evaluate this to begin recording when you like
(fl-open out *fport-out2*)
;; it begins to print the counted number in the shell window,
;; so you can memorize the place when you find nice phrase/rhythm etc,
;; then you can re-play that place by fl-open-ff . 
;; you can change f-get-4play-data's 2nd arg's value #t to #f when
;; printing info bothers you.

;; evaluate this to stop recording at anytime
(fl-close out *fport-out2*)

;; don't stop the music !
;; chnage the above (p (+ 0 .....)) to (p (+ 12)), then re-evaluate it.
;; you hear the higher sounds after this change.

;; then you can hear the lower sounds when evaluate the below line ..
;; because play1 uses p,d value from the file now,
;; and you see the number and data from the file in the shell window.
;; no printing them when f-assign-4play-data's 2nd arg is #f
(fl-open in *fport-in2*)


;; when you evaluate this, reading data from the file stops with printing "close-in",
;; then you hear the higher sounds because of (p (+ 12 ...)), that is, playing
;; random data starts again, not data from the file.
(fl-close in *fport-in2*)

;; when it gets end of file before you do above (fl-close in ....)
;; the same results as above comes with printing "file end and closed ..."

;; and anytime you do above (fl-open in *fport-in2*),
;; you hear the lower sounds because of the file data ...
;; and you can rewind it whenever you do this (fl-open in *fport-in2*). 

;; then you evaluate this, play1 begins to play the data from 11th to the last
;; on the file, you can do this at any time. It's possible to do this again
;; without waiting the end of file.
(fl-open-ff *fport-in2* 10)

;; and by next code, play1 plays from 11th to 20th, then stops to reading,
;; then play1 plays random data again as (define play1 ....)
;; and you can re-evaluate this code while the preceding this code is running,
;; so you can do this again while paying data is between 11th - 20th,
;; then play1 plays from 11th again, or with different argument values that
;; makes play1 play the data of another place on the same file,
;; at anytime you like, as many as you like.
;; if you have some notes that show the place you like, the number of data place,
;; printed number while recording by f-get-4play-data,
;; it's this function that uses those number.
(fl-open-ff *fport-in2* 10 20)

;; While the file is closed, e.g., (fl-close in ...) or "file end and closed",
;; (fl-open out *fport-out2*) makes it's new recording start again,
;; You can do this as many times as you want.
;; Don't forget (fl-close out *fport-out2*) to close the file.

;; end
(define play1 (lambda ()))

;; You can write or edit the file directly, too, of course !!
;; this data file is (value1 value2 ..) (value1 value2 .....) .... just simple!
;; It reads one list at every time.


;; p.s.
;; I tried above functions on a file consists of 7980 lists, sum of duration is 4480 beat,
;; it meant the data to play for 37.3 min by 120bpm. It's enough long.
;; This code (fl-open-ff *fport* 7970) was evaluated many times befor it's over,
;; and it did that FF without any delay or stagnation.


;; These are tiny tools for the recorded list data file.

;; 1.
;; This returns number of list, beat, time from the data like
;; (val1 val2 val3 ....) (...) .. on the file.
;; usage: (count-time "/.../fname.txt/ (*metro* 'get-tempo) n)
;;          or
;;        (count-time "/.../fname.txt/ 90 n)  ; 90 is your bpm 
;;   n is position of duration value in list,
;;   2 for (pitch dur), 3 for (pitch vol dur) etc ...
;;   
(define count-time
  (lambda (fname bpm place-dur) ; 3rd var: place of duration in a list, 1 or 2 or ....
    (let ((fp (open-input-file fname)))
      (let loop((n 0) 
(ans 0)
(lis (read fp)))
(if (eof-object? lis)
   (begin
     (close-input-port fp)
     (println n 'list, ans 'beat, (exact->inexact (/ ans bpm)) 'min,
      'by (real->integer bpm) 'bpm))
   (loop (+ n 1)(+ ans (list-ref lis (- place-dur 1))) (read fp)))))))


;; when playing the data with the current bpm
(count-time (get '*fport-out2* 'fname) (*metro* 'get-tempo) 2)
; --> 501 list, 1131/4 beat, 2.356250 min, by 120 bpm

;; when playing the same data with a different bpm.
(count-time (get '*fport-out2* 'fname) 90 2)
; --> 501 list, 1131/4 beat, 3.141667 min, by 90 bpm


;; 2.
;; This writes the list data you want on the file to another file.
;; usage:
;; (f-clip "/../file1" "/../file2" 0)   -> write 1st to the last list on file1 to file2
;; (f-clip "/../file1" "/../file2" 3)   -> write 4th to the last list on file1 to file2
;; (f-clip "/../file1" "/../file2" 0 5) -> write 1st to 5th list on file1 to file2
;; (f-clip "/../file1" "/../file2" 2 5) -> 3rd to 5th,   .... like fl-open-ff .

(define f-clip
  (lambda (targ-f new-f n1 . n2)
    (let ((f-port-in (open-input-file targ-f))
 (f-port-out (open-output-file new-f))
 (end-n (if (null? n2) 0 (car n2))))
      (let loop ((n 1)
(lis (read f-port-in)))
(cond ((or (eof-object? lis)
  (and (not (= end-n 0))
(> n end-n)))
      (close-input-port f-port-in)
      (close-output-port f-port-out))
     (else
      (if (> n n1) ;-> write n+1 to n2,  (>= n n1) --> write n1 to n2
  (write lis f-port-out))
      (loop (+ n 1) (read f-port-in))))))))


(f-clip (get '*fport-out2* 'fname) "/.. your-file-path../newfile.txt" 1 5) 


2021年5月30日日曜日 15:59:29 UTC+9 Minoru:
Reply all
Reply to author
Forward
0 new messages