summaryrefslogtreecommitdiff
path: root/marks.fs
blob: 2dc28137d894f2c5513a0eec5423ee9b50c7917b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
\ marks.fs -- marks.scm|rb -> marks.fs

\ Author: Michael Scholz <mi-scholz@users.sourceforge.net>
\ Created: 05/12/27 19:22:06
\ Changed: 17/12/02 07:56:15
\
\ @(#)marks.fs	1.28 12/2/17

\ Commentary:
\
\ add-named-mark	( samp name snd chn -- mark )
\ mark-name->id		( name -- m )
\ move-syncd-marks	( sync diff -- )
\ describe-mark		( id -- ary )
\
\ save-mark-properties	( -- )
\ mark-click-info	( id -- #t )
\ marks->string		( snd -- str )

\ Code:

require clm
require examp

<'> integer? alias channel?

\ snd #f: all sounds
\ chn #f: all channels
: marks-length <{ :optional snd #f chn #f edpos #f -- len }>
	snd sound? if
		chn channel? if
			snd chn edpos marks
		else
			snd chn edpos marks car
		then
	else
		snd chn edpos marks car car
	then length
;

: marks? ( :optional snd chn edpos -- f )
	marks-length 0>
;

\ from rubber.fs
: add-named-mark { samp name snd chn -- mark }
	samp snd chn add-mark { m }
	m name set-mark-name drop
	m
;

\ mark-name->id is a global version of find-mark
: mark-name->id ( name -- m )
	doc" Like find-mark but searche all currently accessible channels."
	{ name }
	#f			\ flag
	sounds each { snd }
		snd channels 0 ?do
			name snd i undef find-mark { m }
			m mark? if
				drop	\ replace #f with mark
				m
				exit
			then
		loop
	end-each
;

: move-syncd-marks ( sync diff -- )
	doc" Move all marks sharing SYNC by DIFF samples."
	{ syn diff }
	syn syncd-marks each { m }
		m undef mark-sample diff + { val }
		m val set-mark-sample drop
	end-each
;

: describe-mark ( id -- ary )
	doc" Return a description of the movements of mark ID over \
the channel's edit history."
	{ id }
	id <'> mark-home 'no-such-mark nil fth-catch if
		sounds each { snd }
			snd channels 0 ?do
				0 snd i ( chn ) edits each
					+
				end-each 1+ ( max-edits ) 0 ?do
					snd j ( chn ) #f marks { m }
					m
					id m array-member? && if
						#( snd j ( chn ) )
						leave
					then
				loop
			loop
		end-each
	then { mark-setting }
	mark-setting array? if
		mark-setting 0 array-ref { snd }
		mark-setting 1 array-ref { chn }
		#( #( 'mark id
		      'sound snd snd short-file-name
		      'channel chn ) ) { descr }
		0 snd chn edits each
			+
		end-each 1+ 1 ?do
			descr
			snd chn i marks id array-member? if
				id i mark-sample
			else
				#f
			then array-push drop
		loop
		descr
	else
		'no-such-mark #( "%s: %s" get-func-name id ) fth-throw
	then
;

\ --- Mark Properties ---
hide
: mark-writeit { mp mhome msamp io -- }
	io "\t%S 0 find-sound to snd\n" #( mhome car file-name ) io-write-format
	io "\tsnd sound? if\n" io-write
	io "\t\t%d snd %d find-mark to mk\n"
	    #( msamp mhome cadr ) io-write-format
	io "\t\tmk mark? if\n" io-write
	io "\t\t\tmk %S set-mark-properties drop\n" #( mp ) io-write-format
	io "\t\tthen\n" io-write
	io "\tthen\n" io-write
;

: save-mark-properties-cb <{ filename -- }>
	undef undef undef marks car car cons? if
		filename :fam a/o io-open { io }
		io "\n\\ from save-mark-properties in %s\n"
		    #( *filename* ) io-write-format
		io "require marks\n\n" io-write
		io "let: ( -- )\n" io-write
		io "\tnil nil { snd mk }\n" io-write
		undef undef undef marks each ( snd-m )
			each ( chn-m )
				each { m }
					m mark-properties { mp }
					mp if
						m mark-home { mhome }
						m undef mark-sample { msamp }
						mp mhome msamp io mark-writeit
					then
				end-each
			end-each
		end-each
		io ";let\n" io-write
		io io-close
	then
;
set-current

: save-mark-properties ( -- )
	doc" Set up an after-save-state-hook \
function to save any mark-properties."
	after-save-state-hook <'> save-mark-properties-cb add-hook!
;
previous

: mark-click-info <{ id -- #t }>
	doc" A mark-click-hook function that describes a \
mark and its properties.\n\
mark-click-hook <'> mark-click-info add-hook!."
	id mark-name { name }
	id undef mark-sample { samp }
	id mark-home car { snd }
	id mark-sync { syn }
	id mark-properties { props }
	"\n   mark id: %s\n\n" #( id ) string-format
	    make-string-output-port { prt }
	name empty? unless
		prt "      name: %s\n" #( name ) port-puts-format
	then
	prt "    sample: %s (%.3f secs)\n"
	    #( samp samp snd srate f/ ) port-puts-format
	syn if
		prt "      sync: %s\n" #( syn ) port-puts-format
	then
	props empty? unless
		prt "properties: %s" #( props ) port-puts-format
	then
	"Mark Info" prt port->string info-dialog drop
	#t
;
\ mark-click-hook <'> mark-click-info add-hook!

\ This code saves mark info in the sound file header, and reads it
\ back in when the sound is later reopened.
: marks->string { snd -- str }
	"\nrequire marks\n" make-string-output-port { prt }
	prt "let: ( -- )\n" port-puts
	prt "\t#f { mk }\n" port-puts
	snd marks each { chan-marks }
		prt "\n\t\\ channel %d\n" #( i ) port-puts-format
		chan-marks each { m }
			m nil? ?leave
			prt "\t%s #f %d %S %d add-mark to mk\n"
			    #( m undef mark-sample
			       j ( chn )
			       m mark-name length 0= if
				       #f
			       else
				       m mark-name
			       then
			       m mark-sync ) port-puts-format
			m mark-properties { props }
			props if
				prt "\tmk %S set-mark-properties drop\n"
				    #( props ) port-puts-format
			then
		end-each
	end-each
	prt ";let\n" port-puts
	prt port->string
;

0 [if]
	output-comment-hook lambda: <{ str -- str' }>
		selected-sound marks->string
	; add-hook!

	after-open-hook lambda: <{ snd -- }>
		snd comment ( str ) <'> string-eval #t nil fth-catch if
			( str ) drop
		then
	; add-hook!
[then]

\ marks.fs ends here