1 SCSoundFileView : SCScope{
3 var <>metaAction, <elasticMode, <drawsWaveForm=true, <readProgress;
4 var <startFrame, <numFrames;
5 var zoomOne, <>dataFrames, <viewFrames, <scrollPos, <>block=64;
7 init{ arg argParent, argBounds;
8 super.init(argParent, argBounds);
9 soundfile = SoundFile.new;
14 if(soundfile.isOpen){^this};
15 if(soundfile.openRead.not){^this};
19 read { |startframe=0, frames, block=64, closeFile=true|
21 if(soundfile.isOpen.not){
22 if(soundfile.openRead.not){
26 startFrame = startframe;
27 frames = frames ? soundfile.numFrames;
29 if (frames == -1) { frames = soundfile.numFrames };
30 numFrames = frames.clip(0, soundfile.numFrames);
32 this.readFile(soundfile, startframe, frames, block);
33 if(closeFile){soundfile.close};
36 readWithTask{|startframe=0, frames, block=64, doneAction, showProgress=true|
37 this.readFileWithTask(soundfile, startframe, frames, block, doneAction, showProgress);
41 this.addDependant(SoundFileViewProgressWindow(soundfile.path.split.last));
44 // needs an open soundfile;
45 readFileWithTask{|soundfile, startframe=0, frames, block=64,
46 doneAction, showProgress=true|
47 var zoomx, o, readtime, data, resampleFrames;
50 this.makeProgressWindow;
52 frames = frames ? soundfile.numFrames;
53 resampleFrames = frames/block;
54 this.drawsWaveForm_(false);
56 zoomx = (resampleFrames/(this.bounds.width-2));
58 var times, frame, data, spec;
59 data = Array(resampleFrames*soundfile.numChannels);
61 times = (frames/o).ceil;
62 spec = [0, times].asSpec;
65 this.read(frame, o, block, false);
67 readProgress = spec.unmap(i);
69 (readtime*0.001).wait;
70 data.addAll(this.data);
71 this.changed(\progress);
74 this.setData(data, block, startframe, soundfile.numChannels, soundfile.sampleRate);
75 this.xZoom_(zoomx).drawsWaveForm_(true).refresh;
79 doneAction.value(this);
81 this.changed(\progressFinished);
85 readFile{|asoundfile, startframe=0, frames=0, block=0, closefile=true|
86 this.setProperty(\readSndFile,
87 [asoundfile, startframe, frames, block,
90 soundfile.numChannels]);
95 // mouseUpAction.value(this, x,y)
99 metaAction.value(this)
102 currentSelection_{|index|
103 this.setProperty(\currentSelection, index);
107 ^this.getProperty(\currentSelection);
110 setSelectionStart{|index,frame|
111 this.setProperty(\selectionStart, [index,frame]);
114 setSelectionSize{|index,frame|
115 this.setProperty(\selectionSize, [index,frame]);
118 setEditableSelectionStart{|index, bool|
119 this.setProperty(\selectionStartIsEditable, [index, bool]);
122 setEditableSelectionSize{|index, bool|
123 this.setProperty(\selectionSizeIsEditable, [index, bool]);
126 setSelectionColor{|index,color|
127 this.setProperty(\selectionColor, [index, color]);
132 array = Array.fill(64, {[0,0]});
133 ^this.getProperty(\selections, array);
136 selectionStart{|index|
137 ^this.getProperty(\selectionStart, index);
140 selectionSize{|index|
141 ^this.getProperty(\selectionSize, index);
145 ^[this.selectionStart(index), this.selectionSize(index)]
147 setSelection { |index, selection|
148 this.setSelectionStart(index, selection[0])
149 .setSelectionSize(index, selection[1]);
152 selectionStartTime{|index|
153 ^this.getProperty(\selectionStartTime, index);
156 selectionDuration{|index|
157 ^this.getProperty(\selectionDuration, index);
160 readSelection{ |block=64, closeFile=true|
162 this.selectionStart(this.currentSelection),
163 this.selectionSize(this.currentSelection),
169 readSelectionWithTask{
171 this.selectionStart(this.currentSelection),
172 this.selectionSize(this.currentSelection)
177 this.setProperty(\gridOn, boolean);
180 gridResolution_{|resolution|
181 this.setProperty(\gridResolution, resolution);
184 gridOn { ^this.getProperty(\gridOn) }
185 gridResolution { ^this.getProperty(\gridResolution) }
186 gridColor { ^this.getProperty(\gridColor, Color.new) }
187 timeCursorOn { ^this.getProperty(\timeCursorOn) }
188 timeCursorPosition { ^this.getProperty(\timeCursorPosition) }
189 timeCursorColor { ^this.getProperty(\timeCursorColor, Color.new) }
192 ^this.getProperty(\getViewNumSamples);
197 arr = Array.newClear(this.dataNumSamples);
198 ^this.getProperty(\getViewData, arr);
202 this.setData(arr, 64, 0, soundfile.numChannels, soundfile.sampleRate);
205 setData{|arr, block=64, startframe = 0, channels=1, samplerate=44100|
207 this.setProperty(\setViewData, [arr, block, startframe, channels, samplerate]);
210 elasticMode_{arg mode;
212 this.setProperty(\elasticResizeMode, mode);
215 drawsWaveForm_{|bool|
216 drawsWaveForm = bool;
217 this.setProperty(\drawsWaveForm, bool);
220 timeCursorPosition_{|frame|
221 this.setProperty(\timeCursorPosition, frame);
225 this.setProperty(\showTimeCursor, bool)
228 timeCursorColor_{|color|
229 this.setProperty(\timeCursorColor, color)
232 zoom {| factor | // zoom factor n or 1/n.
233 this.xZoom = zoomOne.min(this.xZoom * factor);
234 viewFrames = dataFrames * block * (this.xZoom / zoomOne);
235 if ( this.x > (soundfile.numFrames - viewFrames), {
236 this.x_(soundfile.numFrames - viewFrames)
241 zoomToFrac { arg frac; // 0..1
242 this.xZoom = (frac * zoomOne);
243 viewFrames = dataFrames * block * (this.xZoom / zoomOne);
244 if ( this.x > (soundfile.numFrames - viewFrames), {
245 this.x_(soundfile.numFrames - viewFrames)
251 this.x_(0); this.xZoom = zoomOne; this.refresh;
252 viewFrames = dataFrames * block * (this.xZoom / zoomOne);
256 zoomSelection {| index | // selection index
257 if ( this.selectionSize(index) > 0, {
258 this.x_(this.selectionStart(index));
259 this.xZoom = this.selectionSize(index) / (this.bounds.width-2) / block;
260 viewFrames = dataFrames * block * (this.xZoom / zoomOne);
266 scrollTo { | position | // absolute. from 0 to 1
267 this.x_((soundfile.numFrames - viewFrames) * position).refresh;
271 scroll {| amount | // +/- range in viewFrames
272 this.x_((this.x + (amount*viewFrames))
273 .clip(0,soundfile.numFrames - viewFrames)).refresh;
283 this.x_(soundfile.numFrames - viewFrames ).refresh;
287 selectAll {| index | // selection index
288 this.setSelectionStart(index, 0); this.setSelectionSize(index, this.soundfile.numFrames)
291 selectNone {| index | // selection index
292 this.setSelectionSize(index, 0); // sends x to 0 when selection is not full width visible? ( thus update scrollPos )
297 this.setProperty(\gridOffset, offset);
303 scrollPos = this.x / (soundfile.numFrames - viewFrames)
308 dataFrames = this.dataNumSamples/this.soundfile.numChannels;
309 zoomOne = dataFrames / (this.bounds.width-2);
310 viewFrames = dataFrames * block * (this.xZoom / zoomOne);
313 *paletteExample { arg parent, bounds;
315 example = this.new(parent, bounds);
316 file = SoundFile.new;
317 file.openRead("sounds/a11wlk01.wav");
318 example.soundfile = file;
319 example.read(0, file.numFrames);
325 SoundFileViewProgressWindow{
329 ^super.new.makeWindow(name)
333 win = SCWindow.new("reading: " ++ name,
334 Rect(100,100,300, 40), false).front;
335 win.view.decorator = FlowLayout(win.view.bounds);
336 slider = SCRangeSlider(win, Rect(4,4,290,10));
339 update{|changed, changer|
341 if(changer === \progress){
342 {slider.lo_(0).hi_(changed.readProgress)}.defer
345 if(changer === \progressFinished){
347 changed.removeDependant(this)}.defer;
354 /* jan truetzschler 2005 */