Check-in [7b49ef72bc]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:release 2.1.6 {2002 03 07}
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | release-2-1-6
Files: files | file ages | folders
SHA1: 7b49ef72bc1da90db3fb2f38a9d3073accd7d446
User & Date: pooryorick 2015-10-02 03:05:56
Context
2015-10-02
03:07
release 2.2.2 {2003 05 09} check-in: ee325c8432 user: pooryorick tags: release-2-1-6
03:05
release 2.1.6 {2002 03 07} check-in: 7b49ef72bc user: pooryorick tags: release-2-1-6
02:50
release 2.0.7 {2001 03 16} Leaf check-in: 7e3a392c77 user: pooryorick tags: release-2-0-7
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to snack/README.

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

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
-
+












-
-
+
+
-


-
+




-
+



-
-
+
+


-
+



-
-
+
+

-
+

















-
+







Snack v2.0 - a sound toolkit for scripting languages
Snack v2.1 - a sound toolkit for scripting languages

Kåre Sjölander <kare@speech.kth.se>



Introduction
-------------------------------------------------------------------

Snack is a sound processing toolkit designed as an extension
to a scripting language. Snack currently works with the scripting
languages Tcl/Tk and Python.
Snack has commands to play, record, process, and visualize sound.
Snack supports in-memory sound objects, file based
audio, and streaming audio. It handles fileformats such as WAV, AU, AIFF,
Snack provides high level sound objects, with flexible storage management,
and streaming support. It handles most common sound file formats.
and MP3.
The visualization canvas item types update in real-time and can output
postscript. The same scripts run on Unix (Linux, Solaris, HP-UX, IRIX,
FreeBSD, NetBSD), Macintosh, and Windows 95/98/NT/2000. It is also possible
FreeBSD, NetBSD), Macintosh, and Windows 95/98/NT/2000/XP. It is also possible
to run scripts embedded in web pages through the use of the Tcl plug-in.
Several example scripts can be found in the demos directory.

For more information on Tcl/Tk and Python see
Tcl/Tk: http://dev.scriptics.com/
Tcl/Tk: http://tcl.activestate.com/
Python: http://www.python.org/

In order to use Snack you must have Tcl and Tk version 8.0 or later. Always 
use the latest stable release, currently 8.3.2, which can be downloaded from 
ftp://ftp.scriptics.com/pub/tcl/.
use the latest stable release, currently 8.3.4, which can be downloaded from 
ftp.activestate.com/ActiveTcl/html/.

Tcl/Tk is often included with Python distributions. Snack has been tested
with Python 1.5.2 - 2.0 on Linux and Windows. See the Python
with Python 1.5.2 - 2.1 on Linux and Windows. See the Python
section below.

The Snack package has been tested on the following platforms:
Windows 95/98/NT/2000
Linux 2.0.35 (OSS 3.5) - 2.2.14 (OSS 3.8.2) (x86 and PowerPC)
Windows 95/98/NT/2000/XP
Linux 2.0.35 (OSS 3.5) - 2.4.3 (OSS 3.8.2) (x86 and PowerPC)
SunOS 5.5.1 (Sparc and x86), Solaris 8 (Sparc)
HP-UX B.10.20
HP-UX B.10.20/11.00
IRIX 6.2, 6.3 & 6.4 (even runs under SoftWindows, although slowly)
NetBSD-current/i386 using the OSS emulation library
BSD/OS-4.1
MacOS 8.6

Make sure you have the latest Snack version available at
http://www.speech.kth.se/snack/ before proceeding with the installation.



Compilation instructions for Snack on Unix
-------------------------------------------------------------------

You must have Tcl/Tk installed on your system. Both Tcl and Tk must have
been configured with the "--enable-shared" flag at build time (this is 
default for the 8.3 versions). Build them before Snack.

Unpack Snack and change directory to the snack2.0.7/unix directory.
Unpack Snack and change directory to the snack2.1.6/unix directory.

Type "./configure".

If you get this error message "Can't find Tcl configuration definitions",
you have to specify their locations using the options "--with-tcl" and
"--with-tk" when running configure. For example, use 
"--with-tcl=/usr/lib --with-tk=/usr/lib" if Tcl/Tk was
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
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







-
+

-
+

-
+















-
+

-
+







contains the Tcl header file (tcl.h). The same goes for TK_INCPATH (tk.h). 
XINCLUDES should be the path to the directory containing the X11 include
files.

Summary in case you download Tcl, Tk, and Snack and build from scratch:
You should place the distributions in the same directory and unpack them.
Build Snack using the following commands:
cd tcl8.3.1/unix
cd tcl8.3.4/unix
./configure --enable-shared
cd ../../tk8.3.1/unix
cd ../../tk8.3.4/unix
./configure --enable-shared
cd ../../snack2.0.7/unix
cd ../../snack2.1.6/unix
./configure
make

If you use Tcl/Tk 8.0 to 8.0.5 you change the last configure to
configure --disable-stubs



Testing
-------------------------------------------------------------------

When you have succesfully compiled Snack it's time to look at the demos.
In order to run these you will have to set the environment variable 
TCLLIBPATH to the directory containing the Snack library files (you don't 
need this step if you install Snack as described below). If you have 
compiled Snack in /u/kare/snack2.0.7/unix, this would be:
compiled Snack in /u/kare/snack2.1.6/unix, this would be:

setenv TCLLIBPATH /u/kare/snack2.0.7/unix
setenv TCLLIBPATH /u/kare/snack2.1.6/unix

Change to the demos/tcl/ directory and type ./widget.tcl:

cd ../demos/tcl/
./widget.tcl

this runs the Snack widget demonstration.
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
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







-
-
+
+

-
-
+
+
+
+
+
+
+








+
+
-
-
+
+







make install



Compilation instructions for Snack on Windows
-------------------------------------------------------------------

The workspace and project files necessary to build Snack on Windows are
in the win directory of the source distribution.
The MSVC++ workspace and project files necessary to build Snack on Windows
are located in the win directory of the source distribution.

In order to use Snack you will have to install Tcl/Tk 8.3 first, don't forget
to tick the box to install include and library files.
In order to use Snack you will have to install Tcl/Tk 8.3 first.

Snack's project files are set up for use with Tcl installed in C:\Tcl\, it
might be easiest to change such paths by editing all *.dsp files in a text
editor.
Don't forget to copy the files snack.tcl and pkgIndex.tcl.dll from the
unix directory to C:\Tcl\lib\snack2.1\ and rename the last file pkgIndex.tcl



Using Snack with Python
-------------------------------------------------------------------

Snack must currently be used in conjunction with Tkinter. You need to have a
matching installation of Snack and Tcl. For example, Python 1.5.2 uses
Tcl8.0.5 and Python 1.6-2.1 uses Tcl8.3 on Windows. For Unix you have to
edit Modules/Setup before building Python to specify which Tcl version to use.
Tcl8.0.5 and Python 1.6-2.0 uses Tcl8.3. You can check this by typing the
following lines at the Python prompt:
The default is Tcl8.0. You can check this by typing the following lines
at the Python prompt:

import Tkinter
Tkinter.Tk().tk.eval('info tclversion')

Snack is accessed using the tkSnack module located in the python directory.
You need to put the file tkSnack.py in your Python path. 

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
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
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271







-
-
-
-
+
+
+
+













-
-
+
+
+







-
+
+
+


-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







copied to "/usr/local/lib/netscape/tclplug/2.0/".
If you have placed the Netscape plug-in somewhere else (e.g. locally in 
$HOME/.netscape/) use:

./configure --enable-plugin --with-mozilla=$SOMEWHERE

You can also simply copy the files yourself to get something similar to this:
/usr/local/lib/netscape/tclplug/2.0/snack2.0/unix/libsnack.sl
/usr/local/lib/netscape/tclplug/2.0/snack2.0/unix/libsound.sl
/usr/local/lib/netscape/tclplug/2.0/snack2.0/unix/pkgIndex.tcl
/usr/local/lib/netscape/tclplug/2.0/snack2.0/unix/snack.tcl
/usr/local/lib/netscape/tclplug/2.0/snack2.1/unix/libsnack.sl
/usr/local/lib/netscape/tclplug/2.0/snack2.1/unix/libsound.sl
/usr/local/lib/netscape/tclplug/2.0/snack2.1/unix/pkgIndex.tcl
/usr/local/lib/netscape/tclplug/2.0/snack2.1/unix/snack.tcl

Currently you need to set this environment variable before starting Netscape:
setenv TCL_PLUGIN_WISH 1

In some cases this may also be necessary:
setenv NPX_PLUGIN_PATH $HOME/.netscape/plugins/



Using Snack with NIST/Sphere file formats
-------------------------------------------------------------------

It is possible to configure Snack to create an additional package for
handling the NIST/Sphere file formats. Use the configure option
--with-nist=DIR to specify the location of the NIST/Sphere distribution,
handling the NIST/Sphere file formats. Use the configure options
--with-nist-include and --with-nist-lib to specify the locations of
the corresponding directories of the NIST/Sphere distribution,
which can be downloaded at
ftp://jaguar.ncsl.nist.gov/pub/sphere_2.6a.tar.Z. In the Sphere
distribution you will have to modify the file src/scripts/install.sh and add
the compilation flag to create position independent code in some cases. Look
at the Snack Makefile for these.

On HP-UX with HP cc use: -Ae +z

Linux users should specify platform: 10 (Custom),
compiler flags: -O -Wall -fPIC, architecture: INTEL,and comment the
line "extern char *sys_errlist[];" in nist/src/lib/sp/exit.c
See SphereFile.txt for more info.

Windows users can get a compiled dll at
http://www.speech.kth.se/~kare/libsnacksphere.dll.
Put it in ..Tcl\lib\Snack2.0 (together with libsnack.dll).
Windows users can get a compiled dll at the address
http://www.speech.kth.se/~kare/libsnacksphere.dll
Put it in ..Tcl\lib\Snack2.1 (together with libsnack.dll).

Linux users get a compiled library at the address
http://www.speech.kth.se/~kare/libsnacksphere.so
Put it in the Snack installation directory (together with libsnack.so).



Using Snack with the OGG/Vorbis file format
-------------------------------------------------------------------

It is possible to configure Snack to create an additional package for
handling the OGG/Vorbis file format. Use the configure options
--with-ogg-include and --with-ogg-lib to specify the locations of an
existing OGG/Vorbis installation.
More information about OGG/Vorbis available at http://www.vorbis.com/

Windows users can get a compiled dll at the address
http://www.speech.kth.se/~kare/ogg.tar.gz
Put libsnackogg.dll in ..Tcl\lib\Snack2.1 (together with libsnack.dll).

Linux users can get a compiled library at the address
http://www.speech.kth.se/~kare/ogg.tar.gz
Put libsnackogg.so in the Snack installation directory (together 
with libsnack.so).

When building Ogg/Vorbis from source on Unix note that some modifications
to the Makefiles might be necessary. Specify
"AM_CPPFLAGS=-I$prefix/include" "LDFLAGS=-L$exec_prefix/lib"
to get them to find their own installed headers and libraries.
On Solaris force libvorbis to use the native compiler and add
-Dalloca=__builtin_alloca
to prevent the system from using a non-existing alloca.



Dynamic linking problems
-------------------------------------------------------------------

(Sun, Linux, and SGI)
286
287
288
289
290
291
292




327
328
329
330
331
332
333
334
335
336
337







+
+
+
+
Richard Ross-Langley
Uwe Koloska
Kevin Russell
Nicolas Garbe
Tom Wilkason
Jonas Ekeroot
Peter Kabal
Ted Dunning
Andreas Kupries
Erik Allaert
Christian Wegehaupt

Changes to snack/changes.

696
697
698
699
700
701
702
































































































































696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
3/21/01 (bug fix) Fixed problem for spectrogram canvas items that caused a crash in some cases.

3/22/01 (bug fix) Corrected AU file format handler which incorrectly handled Lin8 files as Lin8Offset.

3/23/01 (enhancement) Added read support for files with double (8-byte) samples to AU and WAV file format handlers.

3/23/01 (bug fix) Fixed problems reading sound files containing float samples.

3/27/01 (bug fix) Removed unnecessary limit on the number of channels for audio I/O on the SGI platform.

3/27/01 (bug fix) Fixed problem with data copying that sometimes occured when reallocating from a small size to a much larger one.

3/28/01 (bug fix) Corrected out of bounds problem in the pitch command.

4/10/01 (bug fix) Corrected bug in the snacksphere package for sound files containing fewer samples than specified in the header.

4/15/01 (new feature) New filter type: iir, which implements IIR/FIR filtering. (Dunning)

4/15/01 (new feature) LPC analysis support added in section canvas item and in dBPowerSpectrum command. (Rank)

4/15/01 (enhancement) Slight beautification of Waveform postscript. (Rank)

----------------- Released 2.1b1, 4/17/01 -----------------------

4/24/01 (new feature) Added support for the Ogg/Vorbis file format (SnackOgg.c) through the optional package "snackogg".

5/1/00 (bug fix) Fixed bug in the map filter that occured when re-configuring it with only one value during playback of multi-channel sounds.

5/3/01 (new feature) Added Ogg/Vorbis format support for writing files and for streaming play/record.

5/8/01 (new feature) Added support for encoding in the Ogg/Vorbis file format.

5/8/01 (new feature) Added streaming support for the Ogg/Vorbis file format.

5/8/01 (new feature) Added configureProc member to Snack_FileFormat struct. This makes it possible to configure/get file format specific options, e.g. -bitrate for MP3 format or -nominalbitrate for Ogg.

5/8/01 (feature change) Added objc/objv parameters to putHeaderProc() which allows for file format specific options. Procedure now returns TCL_OK/TCL_ERROR.

5/8/01 (feature change) Changed parameter of writeSamplesProc() and added implementation to support its use in WriteSound().

----------------- Released 2.1b2, 5/9/01 -----------------------

5/11/01 (enhancement) The wrap.tcl executable generator can now compile scripts that use the packages snackogg and snacksphere.

5/20/01 (enhancement) Updated sources and project file for Macintosh to work with CodeWarrior 6.0 and Tcl/Tk8.3.3.

5/20/01 (new feature) Added demos generator.tcl and scale.tcl.

----------------- Released 2.1, 5/21/01 -----------------------

6/6/01 (bug fix) Fixed bug in header parsing of ESPS files (.sd).

6/7/01 (change) Waveform shape files are now saved with a sample rate of 200 in order to conform to the shape sound command.

6/7/01 (change) Modifications to the shape sound command to make it conform to the shape files generated by the waveform canvas items. (Barras)

6/13/01 (new feature) Added demos generator.py and scale.py.

6/18/01 (enhancement) Snack save dialogs now append .wav etc on the Macintosh.

----------------- Released 2.1.1, 6/21/01 -----------------------

6/29/01 (bug fix) Fixed bug during clean-up which occured for the command sequence "sound record", "exit" (Snack_ExitProc()), followed by after handler with "sound destroy".

7/2/01 (enhancement) Added read support for AU sound files with header specifying dataSize = -1.

7/2/01 (change) Changed the Windows binary installer to default to C:\Tcl which is what ActiveTcl-8.3.3 uses.

7/4/01 (bug fix) Fixed problem reading some CSL sample files (.nsp).

7/20/01 (new feature) New sound command 'power', which is used to compute windowed log power values for a sound.

----------------- Released 2.1.2, 7/20/01 -----------------------

8/1/01 (bug fix) Fixed byte order problem with RAW sound streams.

8/1/01 (bug fix) Fixed problem with RAW sound streams which caused a hang, during play, if no samples were received.

8/3/01 (enhancement) The iir filter now supports multi-channel sound.

8/3/01 (new feature) New demo, pitch.tcl.

8/3/01 (new feature) The Snack script compiler, wrap.tcl, now works out-of-the-box on Windows, with the binary distribution, and for Linux with the source distribution, because freeWrap binaries were included.

8/6/01 (bug fix) Fixed memory leak for sounds linked to disk files that occurred for repeteated configure/play sequences.

8/13/01 (change) Changed the Windows binary installer to use the Tcl installation directory from ActiveState's registry entry.

8/13/01 (bug fix) Added missing library definition for the Ogg/Vorbis encoder in configure.in.

----------------- Released 2.1.3, 8/14/01 -----------------------

8/15/01 (enhancement) Overhaul of the configure script. New options --with-nist-include, --with-nist-lib, --with-ogg-include, and --with-ogg-lib replace --with-nist and --with-ogg, in order to facilitate multi-platform builds. Also, --exec-prefix is now used as intended.

10/25/01 (bug fix) Minor fix in the MP3 decoder for gcc v2.96.

10/25/01 (bug fix) CSL files are now written with a correct block size in FORMDS16. (Kabal)

10/25/01 (enhancement) Support for reading AIFF files containing samples with non multiple of 8 number of bits. (Kabal)

10/25/01 (enhancement) Support for reading WAV files with formats that use WAVE_FORMAT_EXTENSIBLE. (Kabal)

10/26/01 (enhancement) Updated the MSVC++ project files match ActiveTcl's directory structure.

10/26/01 (new feature) New demo, phonetogram.tcl.

----------------- Released 2.1.4, 10/29/01 -----------------------

11/9/01 (bug fix) Fixed problem in the configure script which caused Snack to be built without the TCL_81_API flag, which in turn caused problems for the sound data command.

1/9/02 (enhancement) The generator filter now works correctly on multi-channel sounds through channel duplication.

1/10/02 (new feature) New demo, generator2.tcl.

1/9/02 (enhancement) Support for the stereo-only devices.

1/21/02 (enhancement) Configure script now support HP-UX 11.x.

2/4/02 (new feature) Support for variable bit rate MP3 files with XING headers. (Wilkason)

2/4/02 (bug fix) Fixed crash on HP-UX machines without audio server. (Allaert)

----------------- Released 2.1.5, 2/5/02 -----------------------

2/22/02 (enhancement) Support for 96kHz sample rate on Windows/Linux.

2/25/02 (enhancement) Playback support for normalized float, [1.0, -1.0], sounds.

2/27/02 (bug fix) Fixed problem with the 'filter' command and the -end option.

2/28/02 (new feature) New filter type: fade, which implements linear/logarithmic/exponential fade-in/-out.

----------------- Released 2.1.6, 3/4/02 -----------------------

3/6/02 (change) Removed automatic zero-padding of ESPS files, the start_time field can now be accessed using "sndName configure -start_time" instead.

Changes to snack/demos/python/MinSect.py.



1
2
3
4
5
6
7
1
2
3
4
5
6
7
8
9
+
+







#! /usr/bin/env python

from Tkinter import *
from tkSnack import *

root = Tkinter.Tk()

initializeSnack(root)

Changes to snack/demos/python/MinSpeg.py.



1
2
3
4
5
6
7
1
2
3
4
5
6
7
8
9
+
+







#! /usr/bin/env python

from Tkinter import *
from tkSnack import *

root = Tkinter.Tk()

initializeSnack(root)

Changes to snack/demos/python/MinWave.py.



1
2
3
4
5
6
7
1
2
3
4
5
6
7
8
9
+
+







#! /usr/bin/env python

from Tkinter import *
from tkSnack import *

root = Tkinter.Tk()

initializeSnack(root)

Changes to snack/demos/python/echo.py.



1
2
3
4
5
6
7
1
2
3
4
5
6
7
8
9
+
+







#! /usr/bin/env python

from Tkinter import *
from tkSnack import *

root = Tkinter.Tk()

initializeSnack(root)

Added snack/demos/python/generator.py.






























































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#! /usr/bin/env python

from Tkinter import *
from tkSnack import *

root = Tkinter.Tk()

initializeSnack(root)
"""AudioControllerSingleton().playLatency(100)"""

s = Sound()

filt = Filter('generator', 440.0)
        
def play():
   s.stop()
   s.play(filter=filt)
        
def stop():
   s.stop()        

def config(arg):
   type = var.get()
   if var.get() == "sine" :
      shape = 0.0
   elif var.get() == "rectangle" :
      shape = 0.5
   elif var.get() == "triangle" :
      shape = 0.5
   elif var.get() == "sawtooth" :
      type = "triangle"
      shape = 0.0
   else :
      shape = 0.0
   filt.configure(s1.get(), s2.get(), shape, type, -1)

f = Frame(root)
f.pack()

s1 = Scale(f, from_=4000, to=50, label="Frequency", length=200, command=config)
s1.pack(side='left')

s2 = Scale(f, from_=32767, to=0, label="Amplitude", length=200, command=config)
s2.pack(side='left')

s1.set(440.0)
s2.set(20000)

var  = StringVar()
var.set("sine")

menu = OptionMenu(root, var, "sine", "rectangle", "triangle", "sawtooth", "noise")
menu.pack()
root.bind_all("<Button1-ButtonRelease>", config)

fb = Frame(root)
fb.pack(side='bottom')
Button(fb, bitmap='snackPlay', command=play).pack(side='left')
Button(fb, bitmap='snackStop', command=stop).pack(side='left')

root.mainloop()

Added snack/demos/python/notescale.py.






















































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#! /usr/bin/env python

from Tkinter import *
from tkSnack import *

root = Tkinter.Tk()

initializeSnack(root)
"""AudioControllerSingleton().playLatency(100)"""

def playbeep(freq):
   s.stop()
   filt.configure(freq)
   s.play(filter=filt)

def beepC4():
   playbeep(261.6)

def beepD4():
   playbeep(293.7)

def beepE4():
   playbeep(329.7)

def beepF4():
   playbeep(349.3)

def beepG4():
   playbeep(392.1)

def beepA4():
   playbeep(440.0)

def beepB4():
   playbeep(493.9)

def beepC5():
   playbeep(523.3)

s = Sound()

filt = Filter('generator', 440.0, 30000, 0.0, 'sine', 8000)
        
Button(root, text='C4', command=beepC4).pack(side='left')
Button(root, text='D4', command=beepD4).pack(side='left')
Button(root, text='E4', command=beepE4).pack(side='left')
Button(root, text='F4', command=beepF4).pack(side='left')
Button(root, text='G4', command=beepG4).pack(side='left')
Button(root, text='A4', command=beepA4).pack(side='left')
Button(root, text='B4', command=beepB4).pack(side='left')
Button(root, text='C5', command=beepC5).pack(side='left')

root.mainloop()

Added snack/demos/python/oggplay.py.























1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#! /usr/bin/env python
#
# Usage: oggplay.py file.ogg
#
# Note: this script will also play audio files in any other format supported
# by tkSnack

import sys
from Tkinter import *
from tkSnack import *

initializeSnack(Tkinter.Tk())

# Load the Ogg/Vorbis format package

Tk().tk.eval('package require snackogg')

if sys.argv[1:]:
	snd = Sound(file=sys.argv[1])
	snd.play(blocking=1)
else:
	print "Usage: oggplay.py file.ogg"

Added snack/demos/python/polarspec.py.




























































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#! /usr/bin/env python

from Tkinter import *
from tkSnack import *
from math import *

root = Tkinter.Tk()

initializeSnack(root)
snd = Sound()

w = 300
h = 300
s = 100
n = 1024
type = StringVar()
type.set("FFT") 

def stop():
    snd.stop()
    root.after_cancel(id)

def draw():
    if (snd.length() > n) :
        pos = snd.length() - n
        spec = snd.dBPowerSpectrum(start=pos,fftlen=n,winlen=n,analysistype=type.get())
        coords=[]
        f=0.0001
        for val in spec :
            v = 6.282985 * log(f)/log(2.0)
            a = 1.4*(val+s)
            x = w/2+a*cos(v)
            y = h/2+a*sin(v)
            coords.append(x)
            coords.append(y)
            f = f + 16000.0 / n
        c.delete('polar')
        c.create_polygon(coords, tags='polar', fill='green')
    if (snd.length(unit='sec') > 20) :
        stop()
    id = root.after(100,draw)
        
def start():
    pos = 0
    snd.record()
    c.update_idletasks()
    id = root.after(100,draw)

c = SnackCanvas(height=h, width=w, bg='black')
c.pack()
f = Frame()
f.pack()
Button(f, bitmap='snackRecord', fg='red', command=start).pack(side='left')
Button(f, bitmap='snackStop', command=stop).pack(side='left')
Radiobutton(f, text='FFT', variable=type, value='FFT').pack(side='left')
Radiobutton(f, text='LPC', variable=type, value='LPC').pack(side='left')
Button(f, text='Exit', command=root.quit).pack(side='left')

root.mainloop()

Changes to snack/demos/python/python-demos.txt.

1
2
3
4
5
6
7
8

9
10
11

12
13
14

15
16
17















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







-
+


-
+


-
+



+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Included Python demos
--------------------------------------------------------------------------

widget.py
The basic Snack demonstrator.

MinWave.py
Minimal waveform example
Minimal waveform example.

MinSect.py
Minimal section example
Minimal section example.

MinSpeg.py
Minimal spectrogram example
Minimal spectrogram example.

echo.py
Demo of echo filter with interactive parameter modification.

sphere.py
Demo that shows how to read NIST/Sphere format files.

polarspec.py
Polar spectrum plot of microphone input signal.

spectrogram.py
Spectrogram plot of microphone input signal.

generator.py
Simple real-time tone generator.

notescale.py
Example of on-the-fly beep generation.

Added snack/demos/python/spectrogram.py.




























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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#! /usr/bin/env python

from Tkinter import *
from tkSnack import *

root = Tkinter.Tk()

initializeSnack(root)
snd = Sound()

def stop():
    snd.stop()

def start():
    snd.record()

c = SnackCanvas(height=200, width=400, bg='black')
c.pack()
c.create_spectrogram(1,1,sound=snd,width=400,height=200,pixelspersec=200)

f = Frame()
f.pack()
Button(f, bitmap='snackRecord', fg='red', command=start).pack(side='left')
Button(f, bitmap='snackStop', command=stop).pack(side='left')
Button(f, text='Exit', command=root.quit).pack(side='left')

root.mainloop()

Added snack/demos/python/sphere.py.


























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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#! /usr/bin/env python

from Tkinter import *
from tkSnack import *

root = Tkinter.Tk()

initializeSnack(root)

# Load the sphere format package

Tk().tk.eval('package require snacksphere')

snd = Sound()

file = 'test.sph'

print 'reading sphere file \'%s\'' % file
snd.read(file)

print 'playing file \'%s\'' % file
snd.play(blocking=1)

print 'writing wav file \'%s\'' % file
snd.write('new.wav')

Changes to snack/demos/python/widget.py.



1
2
3
4
5
6
7
1
2
3
4
5
6
7
8
9
+
+







#! /usr/bin/env python

from Tkinter import *
from tkSnack import *

root = Tkinter.Tk()

initializeSnack(root)

Added snack/demos/tcl/CSLwithAB.tcl.

































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

# This file shows how to handle CSL/NSP files with both A and B data chunks

package require -exact snack 2.1

set filename CSL_file_with_A_and_B_chunks.nsp

# Read in file using Snack's CSL/NSP decoder, which only gets channel A
# This is done in order to determine the number of samples in each channel

snack::sound s -load $filename

set end [expr [s length] - 1]

# Now read channel A by treating the file as raw data skipping initial
# headers and write it out in a file of its own

s read $filename -fileformat raw -skip 60 -end $end

s write channel_A.wav

# Read channel B by skipping channel A and initial headers and write it

s read $filename -fileformat raw -skip [expr 60 + $end * 2 + 8] -end $end

s write channel_B.wav

exit

Changes to snack/demos/tcl/MinSect.tcl.

1
2
3
4
5

6
7
8
9
10
11
12
1
2
3
4

5
6
7
8
9
10
11
12




-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1

pack [canvas .c -width 300 -height 300]

snack::sound s -load ex1.wav

.c create section 0 0 -sound s -start 6000 -end 6100 -height 300 -width 300

Changes to snack/demos/tcl/MinSpeg.tcl.

1
2
3
4
5

6
7
8
9
10
11
12
1
2
3
4

5
6
7
8
9
10
11
12




-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1

pack [canvas .c -height 200 -width 400]

snack::sound s -load ex1.wav

.c create spectrogram 0 0 -sound s -height 200 -width 400

Changes to snack/demos/tcl/MinWave.tcl.

1
2
3
4
5

6
7
8
9
10
11
12
1
2
3
4

5
6
7
8
9
10
11
12




-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1

pack [canvas .c -width 400 -height 100]

snack::sound s -load ex1.wav

.c create waveform 0 0 -sound s -width 400

Changes to snack/demos/tcl/Section.tcl.

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
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




-
+













+
+
-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1

set width 300
set height 200
set start 0
set end 48000
set stipple ""
set winlen 256
set fftlen 512
set filename section.ps
set topfr 8000
set maxval 0.0
set minval -80.0
set skip 500
set atype FFT
set order 20
set type Hamming
set wtype Hamming
option add *font {Helvetica 10 bold}

pack [ canvas .c -width 400 -height 250]
pack [ canvas .c2 -height 50 -width 400 -closeenough 5]
pack [ label .l -text "Drag markers with left mouse button"]
pack [ frame .f1] -pady 2
pack [ scale .f1.s1 -variable width -label Width -from 10 -to 400 \
39
40
41
42
43
44
45

46
47
48
49
50
51



















52
53
54
55
56
57
58
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







+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    -orient horizontal -length 100 -command [list .c itemconf sect -minvalue ]]\
    -side left
pack [ scale .f1.s6 -variable skip -label "Skip" -from 50 -to 500 \
    -orient horizontal -length 100 -command [list .c itemconf sect -skip ]] \
    -side left

pack [ frame .f2i] -pady 2
pack [ label .f2i.lt -text "Type:"] -side left
tk_optionMenu .f2i.cm type Hamming Hanning Bartlett Blackman Rectangle
.f2i.cm.menu entryconfigure 0 -command {.c itemconf sect -windowtype $type}
.f2i.cm.menu entryconfigure 1 -command {.c itemconf sect -windowtype $type}
.f2i.cm.menu entryconfigure 2 -command {.c itemconf sect -windowtype $type}
.f2i.cm.menu entryconfigure 3 -command {.c itemconf sect -windowtype $type}
.f2i.cm.menu entryconfigure 4 -command {.c itemconf sect -windowtype $type}
tk_optionMenu .f2i.at atype FFT LPC
.f2i.at.menu entryconfigure 0 -command {.c itemconf sect -analysistype $atype;.f2i.e configure -state disabled;.f2i.s configure -state disabled}
.f2i.at.menu entryconfigure 1 -command {.c itemconf sect -analysistype $atype;.f2i.e configure -state normal;.f2i.s configure -state normal}
pack .f2i.at -side left

pack [ label .f2i.lo -text "order:"] -side left
entry .f2i.e -textvariable order -width 3

scale .f2i.s -variable order -from 1 -to 40 -orient horiz -length 60 -show no
pack .f2i.e .f2i.s -side left
.f2i.e configure -state disabled
.f2i.s configure -state disabled
bind .f2i.e <Key-Return> {.c itemconf sect -lpcorder $order}
bind .f2i.s <Button1-Motion> {.c itemconf sect -lpcorder $order}

tk_optionMenu .f2i.cm wtype Hamming Hanning Bartlett Blackman Rectangle
for {set i 0} {$i < 5} {incr i} {
  .f2i.cm.menu entryconfigure $i -command {.c itemconf sect -windowtype $wtype}
}
pack .f2i.cm -side left

pack [ label .f2i.lw -text "window:"] -side left
foreach n {32 64 128 256 512} {
    pack [ radiobutton .f2i.w$n -text $n -variable winlen -value $n \
	-command {.c itemconf sect -winlength $winlen}] -side left
}

Changes to snack/demos/tcl/Spectrogram.tcl.

1
2
3
4
5

6
7
8
9
10
11
12
1
2
3
4

5
6
7
8
9
10
11
12




-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1

set width 300
set height 200
set pps 300
set bright 0.0
set contrast 0.0
set winlen 128
34
35
36
37
38
39
40
41
42


43
44
45

46
47
48
49
50
51
52
34
35
36
37
38
39
40


41
42



43
44
45
46
47
48
49
50







-
-
+
+
-
-
-
+







pack [ scale .f1.s5 -variable contrast -label Contrast -from -100 -to 100 -res 0.1 -orient hori -length 100 -command {.c itemconf speg -contrast }] -side left

set topfr 8000
pack [ scale .f1.s7 -variable topfr -label Top -from 1000 -to 8000 -orient hori -length 100 -command {.c itemconf speg -topfr }] -side left

pack [ frame .f2] -pady 2
tk_optionMenu .f2.cm type Hamming Hanning Bartlett Blackman Rectangle
.f2.cm.menu entryconfigure 0 -command {.c itemconf speg -windowtype $type}
.f2.cm.menu entryconfigure 1 -command {.c itemconf speg -windowtype $type}
for {set i 0} {$i < 5} {incr i} {
  .f2.cm.menu entryconfigure $i -command {.c itemconf speg -windowtype $type}
.f2.cm.menu entryconfigure 2 -command {.c itemconf speg -windowtype $type}
.f2.cm.menu entryconfigure 3 -command {.c itemconf speg -windowtype $type}
.f2.cm.menu entryconfigure 4 -command {.c itemconf speg -windowtype $type}
}
pack .f2.cm -side left
pack [ label .f2.lw -text "window:"] -side left
foreach n {32 64 128 256 512 1024 2048} {
    pack [ radiobutton .f2.w$n -text $n -variable winlen -value $n\
	    -command {.c itemconf speg -winlength $winlen}] -side left
}

Changes to snack/demos/tcl/SphereTest.tcl.

1
2
3
4
5

6
7
8
9
10
11

12
13
14
15
16
17
18
1
2
3
4

5
6
7
8
9
10

11
12
13
14
15
16
17
18




-
+





-
+







#!/bin/sh
# the next line restarts using wish \
exec tclsh8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1
package require snacksphere

snack::debug 0
snack::sound s -debug 0

set path "nistlibs"
set path "nist/lib"
set fileList [glob $path/data/ex*.wav] 

foreach file $fileList { 
    puts "Playing: $file"
    s config -file $file
    s play -block 1
}

Changes to snack/demos/tcl/Waveform.tcl.

1
2
3
4
5

6
7
8
9
10
11
12
1
2
3
4

5
6
7
8
9
10
11
12




-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1

set width 400
set height 100
set pps 300
set color black
set stipple ""
set filename waveform.ps

Changes to snack/demos/tcl/aserver.tcl.

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
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




-
+
+
+














-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1
# Try to load optional file format handler
catch { package require snackogg }

snack::debug 0

set port 23654

proc Cmd { sock addr port } {
    global servsock msg

    set cmd [read $sock 4]
    switch $cmd {
	play {
	    set s [snack::sound -debug 0]
	    puts $sock $s ;# return token for this job
	    flush $sock
	    $s config -channel $sock -guessproperties yes
	    $s configure -channel $sock -guessproperties yes
	    $s play -command "[list close $sock]; set msg idle;$s destroy"
	    set msg playing
	}
	stop {
	    set handle [gets $sock] ;# get token (sound name) and stop playback
	    catch { $handle stop }
	    catch { $handle destroy }

Changes to snack/demos/tcl/compose.tcl.

1
2
3
4
5

6
7
8
9
10
11
12
1
2
3
4

5
6
7
8
9
10
11
12




-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1

snack::sound s

set f0 [snack::filter map 0.5]
set f1 [snack::filter echo 0.6 0.6 30 0.4]
set f2 [snack::filter echo 0.6 0.6 50 0.3]
set f3 [snack::filter compose $f0 $f1 $f2]

Changes to snack/demos/tcl/cool.tcl.

1
2
3
4
5
6
7
8


























9
10
11
12
13
14
15
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







-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

# An example of how to build a sound application using Snack.
# Can also be used as a base for specialized applications.

package require -exact snack 2.0
package require -exact snack 2.1
# Try to load optional file format handlers
catch { package require snacksphere }
catch { package require snackogg }

# If they are present add new filetypes to file dialogs
set extTypes  {}
set loadTypes {}
set loadKeys  {}
set saveTypes {}
set saveKeys  {}
if {[info exists snack::snacksphere]} {
    lappend extTypes {SPHERE .sph} {SPHERE .wav}
    lappend loadTypes {{SPHERE Files} {.sph}} {{SPHERE Files} {.wav}}
    lappend loadKeys SPHERE SPHERE
}
if {[info exists snack::snackogg]} {
  lappend extTypes  {OGG .ogg}
  lappend loadTypes {{Ogg Vorbis Files} {.ogg}}
  lappend loadKeys  OGG
  lappend saveTypes {{Ogg Vorbis Files} {.ogg}}
  lappend saveKeys  OGG
}
snack::addExtTypes $extTypes
snack::addLoadTypes $loadTypes $loadKeys
snack::addSaveTypes $saveTypes $saveKeys

set v(debug) 0
snack::sound snd -debug $v(debug)
set v(rate) 16000
set v(width) 600
set v(height) 150
set v(pps) 10

Changes to snack/demos/tcl/dbrec.scr.

1
2

3
4
1

2
3
4

-
+


This is sentence one
This is sentence two
This is sentence two, which is very much longer than the rest in order to illustrate how the font size adapts to fit the window.
This is sentence three
This is sentence four

Changes to snack/demos/tcl/dbrec.tcl.

1
2
3
4
5
6
7

8
9
10
11
12
13
14
1
2
3
4
5
6

7
8
9
10
11
12
13
14






-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

# Prompted sentence recording application
 
package require -exact snack 2.0
package require -exact snack 2.1

set rate 16000
snack::sound t -rate $rate
snack::sound s -rate $rate


# dbrec.tcl menus
62
63
64
65
66
67
68
69
70
71
72
73







74
75
76
77
78
79
80
62
63
64
65
66
67
68





69
70
71
72
73
74
75
76
77
78
79
80
81
82







-
-
-
-
-
+
+
+
+
+
+
+







snack::levelMeter .f1.lm -width 20 -length 200
label .f1.level -textvariable level

# Arrow key descriptions

frame .f1.f
grid [frame .f1.f.g]
grid [label .f1.f.g.lc -text <Space>=Play -relief raised -bd 3] -row 2 -col 1 -padx 20
grid [label .f1.f.g.lu -text <Up>=Record -relief raised -bd 3] -row 1 -col 3
grid [label .f1.f.g.ll -text <Left>=Prev -relief raised -bd 3] -row 2 -col 2
grid [label .f1.f.g.ld -text <Down>=Stop -relief raised -bd 3] -row 2 -col 3
grid [label .f1.f.g.lr -text <Right>=Next -relief raised -bd 3] -row 2 -col 4
grid [label .f1.f.g.lc -text <Space>=Play -relief raised -bd 3] -row 2 \
  -column 1 -padx 20
grid [label .f1.f.g.lu -text <Up>=Record -relief raised -bd 3] -row 1 -column 3
grid [label .f1.f.g.ll -text <Left>=Prev -relief raised -bd 3] -row 2 -column 2
grid [label .f1.f.g.ld -text <Down>=Stop -relief raised -bd 3] -row 2 -column 3
grid [label .f1.f.g.lr -text <Right>=Next -relief raised -bd 3] -row 2 \
  -column 4

pack .f1.bp .f1.br .f1.pr .f1.ne .f1.be .f1.time .f1.lm .f1.level \
    .f1.f -side left
bind .f1.br <ButtonPress-1>   Record
bind .f1.br <ButtonRelease-1> Stop


553
554
555
556
557
558
559
560

561
562
563
564
565
566
567
555
556
557
558
559
560
561

562
563
564
565
566
567
568
569







-
+







#.f1.br configure -state normal
#bind . <KeyRelease-Up> Record
#bind . <KeyPress-Down> Stop


# Use session number specified on command line, otherwise use next slot

if {$argv != ""} {
if {[info exists argv] && $argv != ""} {
  if {[string match "-b" [lindex $argv 0]]} {
    OpenBrowser
    set argv [lreplace $argv 0 0]
  }
  set session [lindex $argv end]
  if {$session != ""} {
    set ::dir [format "sn%04d" $session]

Changes to snack/demos/tcl/echo.tcl.

1
2
3
4
5

6
7
8
9
10
11
12
1
2
3
4

5
6
7
8
9
10
11
12




-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1

set f [snack::filter echo 0.6 0.6 30 0.4 50 0.3]

snack::sound s

pack [frame .f]

42
43
44
45
46
47
48
49
50
51

52
53
54
55
56
57
58
42
43
44
45
46
47
48

49

50
51
52
53
54
55
56
57







-

-
+








proc Config {args} {
  global f v
  $f configure $v(iGain) $v(oGain) $v(delay1) $v(decay1) $v(delay2) $v(decay2)
}

proc Play {} {
  global f
  s stop
  s play -filter $f
  s play -filter $::f
}

proc Load {} {
  set file [snack::getOpenFile -initialdir [file dirname [s cget -file]]]
  if {$file == ""} return
  s config -file $file
}

Changes to snack/demos/tcl/formant.tcl.

1
2
3
4
5

6
7
8
9










10
11
12
13
14
15
16
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




-
+




+
+
+
+
+
+
+
+
+
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1

# there is no way (?) to find out from Tk if we can display UNICODE IPA
# but it seems to be standard on windows installations
if {[string match windows $tcl_platform(platform)]} {set UNICODE_IPA 1}

switch $tcl_platform(platform) {
 windows {
  proc milliseconds { } {clock clicks}
 }
 unix {
  proc milliseconds { } {expr {[clock clicks]/1000}}
 }
}


set vowels(sw) {
 O: u      300 600 2350 3250
 O  \u028a 350 700 2600 3200
 Å: o      400 700 2450 3250
 Å  \u0254 500 850 2550 3250
 A: \u0251 600 950 2550 3300
38
39
40
41
42
43
44
45

46
47

48
49
50
51
52
53
54
48
49
50
51
52
53
54

55
56

57
58
59
60
61
62
63
64







-
+

-
+







 > \u0254 590 880 2540 {}
 U \u028a 450 1030 2380 {}
 u u 310 870 2250 {}
}

set vowels(lang) us
 
proc vok4Create {w} {
proc vok4Create {w {wid 200} {hei 200}} {
 upvar #0 $w a
 frame $w -width 200 -height 200
 frame $w -width $wid -height $hei
 pack [canvas $w.c -bg black] -fill both -expand 1
 pack propagate $w 0
 set a(xm) 20
 set a(ym) 20
 set a(F10) 800
 set a(F11) 200
 set a(F20) 2300
63
64
65
66
67
68
69
70

71
72
73
74
75
76
77
73
74
75
76
77
78
79

80
81
82
83
84
85
86
87







-
+







 $w.m add radiobutton -variable vowels(lang) -value us \
   -command [list vok4Config $w] -label "American vowels (after Ladefoged)"
 $w.m add radiobutton -variable vowels(lang) -value NIL \
   -command [list vok4Config $w] -label "Don't display vowels"
 
 # trailInit $w 10
 
 bind $w.c <ButtonPress-1> "Play;vok4Move $w %x %y"
 bind $w.c <ButtonPress-1> "vok4Move $w %x %y;Play"
 bind $w.c <B1-Motion> [list vok4Move $w %x %y]
 bind $w.c <ButtonRelease-1> "Stop"
 bind $w.c <Configure> [list vok4Config $w %w %h]
 bind $w.c <ButtonPress-3> [list tk_popup $w.m %X %Y]
 return $w
}

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
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







+


-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-







   set y [expr {$a(y0)+($a(y1)-$a(y0))*($f1-$a(F10))*1.0/($a(F11)-$a(F10))}]
   $w.c create text $x $y -font "times 16" -anchor c -text $sym -fill gray -tags sym
  }
 }
}

proc vok4Move {w x y} {
# puts [info level 0]
 upvar #0 $w a
 
 if $::v(on) {
  set f1 [expr {int($a(F10)+($a(F11)-$a(F10))*($y-$a(y0))*1.0/($a(y1)-$a(y0)))}]
  set f2 [expr {int($a(F20)+($a(F21)-$a(F20))*($x-$a(x0))*1.0/($a(x1)-$a(x0)))}]
  set ::v(f1) $f1
  set ::v(f2) $f2
  Config
  set a(curx) $x
  set a(cury) $y
  #  trailUpdate $w
 set f1 [expr {int($a(F10)+($a(F11)-$a(F10))*($y-$a(y0))*1.0/($a(y1)-$a(y0)))}]
 set f2 [expr {int($a(F20)+($a(F21)-$a(F20))*($x-$a(x0))*1.0/($a(x1)-$a(x0)))}]
 set ::v(f1) $f1
 set ::v(f2) $f2
 Config
 set a(curx) $x
 set a(cury) $y
 #  trailUpdate $w
 }
 return ""
}

proc updatePreview {} {
 $::v(pGen) configure \
   $::v(g,freq) $::v(g,ampl) [expr 0.01*$::v(g,shape)] $::v(g,type) 1024
 $::v(pF1) configure $::v(f1) $::v(b1)
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
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







+
+













+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







}

proc Play {} {
 set ::v(on) 1
 s stop
 s play -filter $::v(All)
 updatePreview
 set ::v(tstart) [milliseconds]
 #  updateTracks
 .f1.b config -relief sunken
}

proc Stop {} {
 s stop
 set ::v(on) 0
 .f1.b config -relief raised
}

proc Load {} {
 set file [snack::getOpenFile]
 if {$file != ""} {s read $file}
}

proc updateTracks {} {
 set tt 50
 set now [milliseconds]
 set then $::v(tstart)
 set dt [expr 1.0*([milliseconds]-$::v(tstart))]
 #set ::v(g,freq) [expr 100+100*(1.0*$dt/$tt)*exp(-$dt/$tt)]
 set ::v(g,freq) [expr {100+2*cos(2*3.1415*$dt/$tt)}]

 Config

 if $::v(on) {
  after 50 updateTracks
 }
}

proc labeledScale {w args} {
 array set a {-valwidth 4 -labwidth 8}
 array set a $args
 catch {set a(-text) $a(-label)}

 frame $w
197
198
199
200
201
202
203
204
205


206
207
208
209


210
211
212
213
214
215
216
223
224
225
226
227
228
229


230
231
232
233


234
235
236
237
238
239
240
241
242







-
-
+
+


-
-
+
+







 catch {destroy $w}
 toplevel $w
 wm title $w "About: Formant Synthesis Demo"
 set text " This application demonstrates formant-based synthesis
 of vowels in real time, in the spirit of Gunnar Fant's 
 Orator Verbis Electris (OVE-1) synthesizer of 1953.

 Set source and filter parameters to the left. Click and 
 drag in the \"vowel space\" to the right to hear the vowels. 
 Set source and filter parameters at the top. Click and 
 drag in the \"vowel space\" to hear the vowels. 
 Right-click to select target language for vowel symbols.
 
 Waveform and power spectrum of source (red) and 
 output signal (green) are displayed at the bottom.
 Power spectrum of source (red) and output signal (green) are 
 to the right, waveforms are displayed at the bottom.
 
 The source type \"sampled\" will use a sound file 
 containing a single period of a waveform as voice source.

 Copyright © 2000 Jonas Beskow
 Centre for Speech Technology
 KTH, Stockholm"
240
241
242
243
244
245
246
247

248
249
250
251
252
253
254
255
256
257
258
259
260
261
262

263
264
265
266

267
268
269
270
271
272
273
274
275
276




277
278
279
280
281
282
283
284
285
286



287
288
289
290
291


292
293
294

295
296
297
298
299
300

301
302
303
304
305

306
307
308
309
310
311




312
313
314
315
316




317
318

319










320
321
322
323
324
325
326
266
267
268
269
270
271
272

273
274
275
276
277
278
279
280
281
282
283
284
285
286
287

288
289
290
291

292
293
294
295
296
297
298




299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318


319
320
321


322

323
324
325
326

327





328

329




330
331
332
333
334




335
336
337
338
339

340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358







-
+














-
+



-
+






-
-
-
-
+
+
+
+










+
+
+



-
-
+
+

-
-
+
-




-
+
-
-
-
-
-
+
-

-
-
-
-
+
+
+
+

-
-
-
-
+
+
+
+

-
+

+
+
+
+
+
+
+
+
+
+







.m.file add command -label Exit -command exit
.m.help add command -label About... -command About
. configure -menu .m

# Generator GUI

frame .f1 -relief groove -bd 2
grid .f1 -sticky news -padx 5 -pady 5
grid .f1 -row 0 -column 0 -sticky news -padx 5 -pady 5
label .f1.l -text Source -bg red -anchor w
tk_optionMenu .f1.gt v(g,type) rectangle triangle sine sampled noise
button .f1.b -bitmap snackPlay -command Play
button .f1.c -bitmap snackStop -command Stop

labeledScale .f1.gf -label "Freq." -variable v(g,freq) -from 0.0 -to 1000 -resolution 1.0 -orient horiz -command Config
labeledScale .f1.ga -label "Ampl." -variable v(g,ampl) -from 0.0 -to 6000 -resolution 1.0 -length 160 -orient horiz -command Config
labeledScale .f1.gs -label "Shape" -variable v(g,shape) -from 0.0 -to 100 -resolution 1.0 -length 160 -orient horiz -command Config

grid .f1.l .f1.gt .f1.b .f1.c -sticky we -padx 5
grid .f1.gf -columnspan 4 -sticky we
grid .f1.ga -columnspan 4 -sticky we
grid .f1.gs -columnspan 4 -sticky we
grid columnconfigure .f1 0 -weight 1

grid rowconfigure .f1 4 -weight 1
# Formant filter GUI

frame .f2 -relief groove -bd 2
grid .f2 -sticky news -padx 5 -pady 5
grid .f2 -row 0 -column 1 -sticky news -padx 5 -pady 5
label .f2.l -text "Formants" -bg green -anchor w
grid .f2.l -columnspan 5 -sticky we -padx 5 -pady 5
label .f2.lf -text "Frequency" -anchor w
label .f2.lfu -text "Hz "
label .f2.lb -text "Bandwidth" -anchor w
label .f2.lbu -text "Hz "
grid .f2.lf -row 1 -col 1 -sticky w
grid .f2.lfu -row 1 -col 2 -sticky w
grid .f2.lb -row 1 -col 3 -sticky w
grid .f2.lbu -row 1 -col 4 -sticky w
grid .f2.lf -row 1 -column 1 -sticky w
grid .f2.lfu -row 1 -column 2 -sticky w
grid .f2.lb -row 1 -column 3 -sticky w
grid .f2.lbu -row 1 -column 4 -sticky w

for {set i 1} {$i<=4} {incr i} {
 label .f2.l0$i -text F$i -width 2
 scale .f2.f$i -variable v(f$i) -from 0 -to 5000 -resolution 1.0 -orient horiz -command Config -showvalue 0 -bd 1 -width 10
 label .f2.l1$i -textvariable v(f$i) -anchor w -width 4
 scale .f2.b$i -variable v(b${i}) -from 1.0 -to 500 -resolution 1.0 -orient horiz -command Config -showvalue 0 -bd 1 -width 10 -length 80
 label .f2.l2$i -textvariable v(b$i) -anchor w -width 3
 grid .f2.l0$i .f2.f$i .f2.l1$i .f2.b$i .f2.l2$i -sticky news
}
grid columnconfigure .f2 1 -weight 1

set vokh 250
set vokw 275

# Vowel space

vok4Create .voc
grid .voc -row 0 -col 1 -rowspan 2 -sticky news
vok4Create .voc $vokw $vokh
grid .voc -row 1 -column 0 -sticky news

# Waveforms preview

# Spectrum section preview
set prew 550

snack::sound preview1
snack::sound preview2


set secw $vokw
canvas .c1 -bg black -height 100 -width $prew
grid .c1 -columnspan 2 -sticky news
.c1 create waveform 0 50 -anchor w -sound preview1 -fill red  -height 90 -pixelspersecond 16000
.c1 create waveform 0 50 -anchor w -sound preview2 -fill green  -height 90 -pixelspersecond 16000

set sech $vokh
# Spectrum section preview

canvas .c2 -bg black -height 100 -width $prew
grid .c2 -columnspan 2 -sticky news
.c2 create section 0 50 -anchor w -sound preview1 -fill red -height 90 -topfrequency 8000 -width $prew -preemphasis 10 -maxval 40 -tags sect
.c2 create section 0 50 -anchor w -sound preview2 -fill green -height 90 -topfrequency 8000 -width $prew -preemphasis 10 -maxval 40 -tags sect
canvas .c2 -bg black -height 100 -width $secw
grid .c2 -row 1 -column 1  -sticky news
.c2 create section 0 0 -sound preview1 -fill red -height $sech -topfrequency 4000 -width $secw -analysistype lpc -tags sect -maxvalue 30
.c2 create section 0 0 -sound preview2 -fill green -height $sech -topfrequency 4000 -width $secw -analysistype lpc -tags sect -maxvalue 30

foreach freq {1 2 3 4 5 6 7 8} {
 set x [expr {$freq*$prew/8.0}]
 .c2 create line $x 0 $x 100 -fill #666666
 .c2 create text $x 0 -anchor ne -text $freq -fill #666666
foreach freq {1 2 3 4} {
 set x [expr {$freq*$secw/4.0}]
 .c2 create line $x 0 $x $sech -fill #999999
 .c2 create text $x 0 -anchor ne -text $freq -fill #999999
}
.c2 create text 0 0 -anchor nw -text kHz -fill #666666
.c2 create text 0 0 -anchor nw -text kHz -fill #999999
.c2 raise sect

# Waveforms preview

set wavw 550
set wavh 90

canvas .c1 -bg black -height 100 -width $wavw
grid .c1 -row 2 -columnspan 2 -sticky news
.c1 create waveform 0 50 -anchor w -sound preview1 -fill red  -height $wavh -pixelspersecond 16000
.c1 create waveform 0 50 -anchor w -sound preview2 -fill green  -height $wavh -pixelspersecond 16000

# Default values

set v(f1) 500
set v(b1) 50
set v(f2) 1500
set v(b2) 75

Changes to snack/demos/tcl/fourChan.tcl.

1
2
3
4
5

6
7
8
9
10
11
12
1
2
3
4

5
6
7
8
9
10
11
12




-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1

# Create a four channel sound with some computed waveform data

sound s -channels 4 -rate 8000
s length 16000
set p 16
set n 0

Added snack/demos/tcl/freewrap.

cannot compute difference between binary files

Added snack/demos/tcl/generator.tcl.

























































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.1

set f [snack::filter generator 440.0]
snack::sound s
#snack::audio playLatency 200

tk_optionMenu .m v(type) sine rectangle triangle sawtooth noise
foreach i [list 0 1 2 3 4] {
  .m.menu entryconfigure $i -command Config
}
pack .m -side bottom

pack [frame .fb] -side bottom
pack [button .fb.a -bitmap snackPlay -command Play] -side left
pack [button .fb.b -bitmap snackStop -command "s stop"] -side left

set v(freq) 440.0
set v(ampl) 20000

pack [frame .f] -expand yes -fill both -side top
pack [scale .f.s1 -label Frequency -from 4000 -to 50 -length 200\
        -variable v(freq) -command Config] -side left -expand yes -fill both
pack [scale .f.s2 -label Amplitude -from 32767 -to 0 -length 200\
        -variable v(ampl) -command Config] -side left -expand yes -fill both

proc Config {args} {
  global f v
  set shape 0.0
  set type $v(type)
  switch $type {
    sine {
      set shape 0.0
    }
    rectangle {
      set shape 0.5
    }
    triangle {
      set shape 0.5
    }
    sawtooth {
      set shape 0.0
      set type triangle
    }
  }
  $f configure $v(freq) $v(ampl) $shape $type -1
}

proc Play {} {
  global f
  s stop
  s play -filter $f
}

Added snack/demos/tcl/generator2.tcl.













































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.1

snack::sound s1 -channels 2
set leftMap [snack::filter map 1 0 0 0]
set left(generator) [snack::filter generator 440 20000 0.0 sine -1]
set leftFilter [snack::filter compose $left(generator) $leftMap]

snack::sound s2 -channels 2
set rightMap [snack::filter map 0 0 0 1]
set right(generator) [snack::filter generator 440 20000 0.0 sine -1]
set rightFilter [snack::filter compose $right(generator) $rightMap]

pack [frame .fb] -side bottom
pack [button .fb.a -bitmap snackPlay -command Play] -side left
pack [button .fb.b -bitmap snackStop -command "snack::audio stop"] -side left

set left(freq) 440.0
set left(ampl) 20000
set right(freq) 440.0
set right(ampl) 20000

pack [frame .left] -expand yes -fill both -side top
pack [label .left.l -text "Left channel "] -side left
pack [scale .left.s1 -label Frequency -from 4000 -to 50 -length 200\
        -variable left(freq) -command [list Config left]] -side left -expand yes -fill both
pack [scale .left.s2 -label Amplitude -from 32767 -to 0 -length 200\
        -variable left(ampl) -command [list Config left]] -side left -expand yes -fill both
tk_optionMenu .left.m1 left(type) sine rectangle triangle sawtooth noise
foreach i [list 0 1 2 3 4] {
 .left.m1.menu entryconfigure $i -command [list Config left]
}
pack .left.m1 -side left

pack [frame .right] -expand yes -fill both -side top
pack [label .right.l -text "Right channel"] -side left
pack [scale .right.s1 -label Frequency -from 4000 -to 50 -length 200\
        -variable right(freq) -command [list Config right]] -side left -expand yes -fill both
pack [scale .right.s2 -label Amplitude -from 32767 -to 0 -length 200\
        -variable right(ampl) -command [list Config right]] -side left -expand yes -fill both
tk_optionMenu .right.m2 right(type) sine rectangle triangle sawtooth noise
foreach i [list 0 1 2 3 4] {
 .right.m2.menu entryconfigure $i -command [list Config right]
}
pack .right.m2 -side left

proc Config {f args} {
  set shape 0.0
  upvar $f lf
  set type $lf(type)
  switch $type {
    sine {
      set shape 0.0
    }
    rectangle {
      set shape 0.5
    }
    triangle {
      set shape 0.5
    }
    sawtooth {
      set shape 0.0
      set type triangle
    }
  }
  $lf(generator) configure $lf(freq) $lf(ampl) $shape $type -1
}

proc Play {} {
  snack::audio stop
  s1 play -filter $::leftFilter
  s2 play -filter $::rightFilter
}

Changes to snack/demos/tcl/levelmeter.tcl.

1
2
3
4
5

6
7
8
9
10
11
12
1
2
3
4

5
6
7
8
9
10
11
12




-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1

snack::sound s -channels 2

pack [frame .a]
pack [frame .b]
pack [snack::levelMeter .a.left  -width 20 -length 200 \
	-orient horizontal]

Changes to snack/demos/tcl/mapChan.tcl.

1
2
3
4
5

6
7
8
9
10
11
12
1
2
3
4

5
6
7
8
9
10
11
12




-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1

snack::sound s

set v(0) 1
set v(1) 0
set v(2) 0
set v(3) 1

Changes to snack/demos/tcl/mixer.tcl.

1
2
3
4
5
6
7
8
9

10
11
12
13
14

15
16
17
18
19
20
21
1
2
3
4
5
6
7
8

9
10
11

12

13
14
15
16
17
18
19
20








-
+


-

-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

# A cross-platform mixer application that adapts to the capabilities
# of Snack on the machine it is run on.
# Lots of functionality on Linux - play volume only on Windows, currently.

package require -exact snack 2.0
package require -exact snack 2.1

proc Update {} {
  global doMonitor
  snack::mixer update
  if $doMonitor { after 100 Update }
  if $::doMonitor { after 100 Update }
}
bind . <Configure> Update
wm protocol . WM_DELETE_WINDOW exit

pack [frame .f] -expand yes -fill both
pack [checkbutton .r -text Monitor -command Update -variable doMonitor]

Added snack/demos/tcl/notescale.tcl.



























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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.1

set f [snack::filter generator 440.0 30000 0.0 sine 8000]
snack::sound s
#snack::audio playLatency 100

wm resizable . 0 0

proc Beep {freq} {
  $::f configure $freq
  s stop
  s play -filter $::f
}

pack [button .b1 -text C4 -command [list Beep 261.6]] -side left
pack [button .b2 -text D4 -command [list Beep 293.7]] -side left
pack [button .b3 -text E4 -command [list Beep 329.7]] -side left
pack [button .b4 -text F4 -command [list Beep 349.3]] -side left
pack [button .b5 -text G4 -command [list Beep 392.1]] -side left
pack [button .b6 -text A4 -command [list Beep 440.0]] -side left
pack [button .b7 -text B4 -command [list Beep 493.9]] -side left
pack [button .b8 -text C5 -command [list Beep 523.3]] -side left

Added snack/demos/tcl/oggstream.tcl.





































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#!/bin/sh
# the next line restarts using tclsh \
exec wish8.3 "$0" "$@"

# Demonstration that sends a live recorded Ogg/Vorbis stream
# to the Snack sound server, aserver.tcl
# You will have to edit this script to set host and port
# to reflect were the server is run.

package require snack
package require snackogg

# Edit host and port here

set host ior.speech.kth.se
set port 23654

if [catch {set sock [socket $host $port]} res] {
    puts "Error: no aserver.tcl at $host:$port"
    exit
}

# Create sound object and attach it to the opened socket stream
sound s -channel $sock -channels 2 -rate 44100 -fileformat ogg

# Notify the server that a play operation is due
puts -nonewline $sock play

# Set desired bitrate
s config -nominalbitrate 32000

# Start recording
s record

# Keep the event loop alive, necessary for background recording
vwait forever

Added snack/demos/tcl/phonetogram.tcl.
























































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.1

sound s
sound t

pack [frame .b] -side bottom
pack [button .b.r -bitmap snackRecord -command Start -fg red -width 40] \
    -side left  
pack [button .b.s -bitmap snackStop -command Stop -width 40] -side left
pack [button .b.p -bitmap snackPlay -command {Stop;s play} -width 40] \
    -side left
pack [checkbutton .b.l -text "Erase dots" -variable erase] -side left
pack [frame .f] -side top -expand true -fill both
pack [canvas .f.c -bg white] -side left -expand true -fill both
.f.c create text 130 100 -text "Phonetogram plot (pitch and intensity)"

set samplePos 0
set erase 0

proc Stop {} {
  s stop
  after cancel Draw
}

proc Start {} {
  Stop
  s record
  set ::samplePos 0
  .f.c delete all
  after 200 Draw
}

proc Draw {} {
  if {$::erase} { .f.c delete all }
  set length [s length]  
  while {$::samplePos < $length - 666} {
    t copy s -start $::samplePos -end [expr {$::samplePos+665}]
    t changed new
    set pitch [lindex [t pitch] 2]
    set amplitude [t max]
    if {$amplitude < 1} { set amplitude 1 }
    set y [expr {[winfo height .f.c]*(2.0-log10($amplitude)/2.26)}]
    set x [expr {[winfo width .f.c]*($pitch/300.0)}]
    if {$pitch > 0.0} {
      .f.c create oval [expr {$x-1}] [expr {$y-1}] [expr {$x+1}] [expr {$y+1}]
    }
    incr ::samplePos 160
  }
  after 50 Draw
  if {[s length] > 320000} Stop
}

Added snack/demos/tcl/pitch.tcl.























































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.1

sound s
sound t

pack [frame .b] -side bottom
pack [button .b.r -bitmap snackRecord -command Start -fg red -width 40] \
    -side left  
pack [button .b.s -bitmap snackStop -command Stop -width 40] -side left
pack [button .b.p -bitmap snackPlay -command {Stop;s play} -width 40] \
    -side left
pack [label .b.l -text "Draw speed:"] -side left
tk_optionMenu .b.om pixpsec 25 50 100 200
pack .b.om -side left
pack [label .b.l2 -text "pixels per second"] -side left
pack [frame .f] -side top -expand true -fill both
pack [canvas .f.d -width 40 -bg white] -side left -fill y
pack [canvas .f.c -bg white] -side left -expand true -fill both
.f.c create text 150 100 -text "Pitch plot of microphone signal"

set pixpsec 25
set samplePos 0
#.c create spectrogram 0 0 -sound s -height 200 -pixelspersec $pixpsec

proc Stop {} {
  s stop
  after cancel Draw
}

proc Start {} {
  Stop
  s record
  set ::samplePos 0
  set ::ox  0
  set ::oy  0
  .f.c delete all
  .f.c create line 0 $::ty 1280 $::ty -tags target
  after 200 Draw
}

proc Draw {} {
  set length [s length]  
  while {$::samplePos < $length - 666-0*320} {
    t copy s -start $::samplePos -end [expr {$::samplePos+665+0*320}]
    set pitch [lindex [t pitch] 2]
    set x [expr {$::ox + 0.01 * $::pixpsec}]
    set y [expr {[winfo height .f.c]*((300-$pitch)/300.0)}]
    if {$::oy == 0} { set ::oy $y }
    if {$pitch > 0.0 && abs($::oy-$y) < 10} {
      .f.c create oval [expr {$x-1}] [expr {$y-1}] [expr {$x+1}] [expr {$y+1}]
    }
    incr ::samplePos 160
    set ::ox $x
    set ::oy $y
    if {$x > [winfo width .f.c]} Stop
  }
  after 50 Draw
  if {[s length] > 320000} Stop
}

bind .f.c <Configure> Configure

proc Configure {} {
  .f.d delete all
  snack::frequencyAxis .f.d 0 0 40 [winfo height .f.c] -topfr 300
}

set ty 150
.f.c create line 0 $::ty 1280 $::ty -tags target
bind .f.c <1> [list initDrag %x %y]
bind .f.c <B1-Motion> [list Drag %x %y]

proc initDrag {x y} {
  set ::ty [.f.c canvasy $y]
  .f.c coords target 0 $::ty 1280 $::ty
}

proc Drag {x y} {
  set y [.f.c canvasy $y]
  .f.c coords target 0 $::ty 1280 $::ty
  set ::ty $y
}

Changes to snack/demos/tcl/play.tcl.

1
2
3
4
5




6
7
8
9
10
11
12
1
2
3
4

5
6
7
8
9
10
11
12
13
14
15




-
+
+
+
+







#!/bin/sh
# the next line restarts using tclsh \
exec tclsh8.3 "$0" "$@"

package require -exact sound 2.0
package require -exact sound 2.1
# Try to load optional file format handlers
catch { package require snacksphere }
catch { package require snackogg }

if {[llength $argv] == 0} {
  puts {Usage: play.tcl file}
  exit
} else {
  set file [lindex $argv 0]
}

Added snack/demos/tcl/polarspec.tcl.



































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.1

set rate 16000
snack::sound s -rate $rate

# Length of FFT 
set n 1024
set type FFT

# Start recording, create polygon, and schedule a draw in 100 ms

proc Start {} {
  Stop
  set ::pos 0
  .c delete all
  .c create polygon -1 -1 -1 -1 -tags polar -fill green
  s record
  after 100 Draw
}

# Stop recording and updating the plot

proc Stop {} {
  s stop
  after cancel Draw
}

# Calculate spectrum and plot it

proc Draw {} {
  if {[s length] > $::n} {
    set ::pos [expr [s length] - $::n]
    set spec [s dBPowerSpectrum -start $::pos -fftlen $::n -winlen $::n \
	-analysistype $::type]
    set coords {}
    set f 0.0001
    foreach val $spec {
      set v [expr {6.282985 * log($f)/log(2.0)}]
      set a [expr {[winfo height .c]/214.0*($val+100)}]
      set x [expr {[winfo width .c]/2+$a*cos($v)}]
      set y [expr {[winfo height .c]/2+$a*sin($v)}]
      lappend coords $x $y
      set f [expr {$f + 16000.0 / $::n}]
    }
    eval .c coords polar $coords
  }
  after 10 Draw
  if {[s length -unit sec] > 20} Stop
}

# Create simple GUI

pack [ frame .f] -side bottom
pack [ button .f.b1 -bitmap snackRecord -command Start -fg red -width 40] \
    -side left
pack [ button .f.b2 -bitmap snackStop   -command Stop -width 40] -side left
pack [ radiobutton .f.b3 -text FFT -variable type -value FFT] -side left
pack [ radiobutton .f.b4 -text LPC -variable type -value LPC] -side left
pack [ canvas .c -width 300 -height 300 -bg black] -side top -expand true \
    -fill both
.c create text 150 150 -text "Polar spectrum plot of microphone signal" \
    -fill red

Changes to snack/demos/tcl/record.tcl.

1
2
3
4
5

6
7
8
9
10
11
12
1
2
3
4

5
6
7
8
9
10
11
12




-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1

file delete _tmprec.wav
snack::sound t -debug 0
t write _tmprec.wav
snack::sound s -file _tmprec.wav -debug 0

set m [menu .menu]

Changes to snack/demos/tcl/recrplay.tcl.

1
2
3
4
5

6
7
8
9
10
11
12
1
2
3
4

5
6
7
8
9
10
11
12




-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1

snack::sound s

set last 0
set server localhost:23654

proc Start {} {
27
28
29
30
31
32
33
34

35
36
37
38
39
40
41
27
28
29
30
31
32
33

34
35
36
37
38
39
40
41







-
+








    puts -nonewline $sock play

    # Send an AU file header to open the device correctly

    puts -nonewline $sock [s data -fileformat au]

    # Run this procedure again in 200ms
    # Run SendData procedure in 200ms

    after 200 SendData
}

proc Stop {} {
    s stop
}

Changes to snack/demos/tcl/snamp.tcl.

1
2
3
4
5



























6
7
8
9
10
11
12
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




-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1
# Try to load optional file format handlers
catch { package require snacksphere }
catch { package require snackogg }

# If they are present add new filetypes to file dialogs
set extTypes  {}
set loadTypes {}
set loadKeys  {}
set saveTypes {}
set saveKeys  {}
if {[info exists snack::snacksphere]} {
    lappend extTypes {SPHERE .sph} {SPHERE .wav}
    lappend loadTypes {{SPHERE Files} {.sph}} {{SPHERE Files} {.wav}}
    lappend loadKeys SPHERE SPHERE
}
if {[info exists snack::snackogg]} {
  lappend extTypes  {OGG .ogg}
  lappend loadTypes {{Ogg Vorbis Files} {.ogg}}
  lappend loadKeys  OGG
  lappend saveTypes {{Ogg Vorbis Files} {.ogg}}
  lappend saveKeys  OGG
}
snack::addExtTypes $extTypes
snack::addLoadTypes $loadTypes $loadKeys
snack::addSaveTypes $saveTypes $saveKeys


snack::debug 0
snack::sound s -debug 0
snack::sound s2
snack::sound sa

set timestr ""
193
194
195
196
197
198
199




200

201
202
203
204
219
220
221
222
223
224
225
226
227
228
229

230
231
232
233
234







+
+
+
+
-
+




 if [file isdirectory $argv] {
  catch {cd $argv}
 }
}

wm protocol . WM_DELETE_WINDOW exit

set filelist [glob -nocomplain *.mp3 *.wav *.MP3 *.WAV]
if {[info exists snack::snackogg]} {
  set filelist [concat $filelist [glob -nocomplain *.ogg *.OGG]]
}
foreach file [lsort -dictionary [glob -nocomplain *.mp3 *.wav *.MP3 *.WAV]] {
foreach file [lsort -dictionary $filelist] {
    set name [file tail $file]
    set files($name) $file
    .frame.list insert end $file
}

Changes to snack/demos/tcl/spectrum.tcl.

1
2
3
4
5

6
7
8
9
10
11
12
1
2
3
4

5
6
7
8
9
10
11
12




-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1

snack::sound s

array set map {
    0 2
    1 3
    2 4

Changes to snack/demos/tcl/tcl-demos.txt.

49
50
51
52
53
54
55
56

57
58
59
60


61




















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







-
+




+
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
fourChan.tcl
Demo of four channel sound output with channel selection.

echo.tcl
Demo of echo filter with interactive parameter modification.

compose.tcl
Demo of a composed filter, i.e. one map filter pipe-lined with an echo filter.
Demo of a composed filter, a map filter in series with an echo filter.

formant.tcl
Demo of a simple formant speech synthesizer built using Snack filters.

polarspec.tcl
Polar spectrum plot of microphone input signal.

oggstream.tcl
Demo that sends a live recorded Ogg/Vorbis stream to aserver.tcl

generator.tcl
Simple real-time tone generator.

notescale.tcl
Example of on-the-fly beep generation.

CSLwithAB.tcl
Example on how to read CSL/NSP files with A and B data chunks.

pitch.tcl
Draws pitch track of speech recorded from the microphone.

phonetogram.tcl
Draws simple phonetogram, i.e., a pitch/intensity plot.

generator2.tcl
Two channel real-time tone generator.

Changes to snack/demos/tcl/tomAmp.tcl.

10
11
12
13
14
15
16
17

18
19
20
21
22
23
24
10
11
12
13
14
15
16

17
18
19
20
21
22
23
24







-
+







set tomAmp(Console) 0
set tomAmp(p) 0
set tomAmp(pause) 0
set tomAmp(elapsed) 0
set tomAmp(current) {}
set tomAmp(currentMP3) {}
;# Setup sound settings
package require -exact snack 2.0
package require -exact snack 2.1
# Buttons
option add *font {Helvetica 10 bold}
option add *Button.activeBackground yellow
option add *Button.borderwidth 1
option add *Button.relief raised
option add *Entry.background lightyellow
option add *Entry.foreground black

Changes to snack/demos/tcl/widget.tcl.

1
2
3
4
5

6
7
8
9
10
11
12
1
2
3
4

5
6
7
8
9
10
11
12




-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
package require -exact snack 2.1
package require http

option add *font {Helvetica 10 bold}
set home http://www.speech.kth.se/snack/
set version ""
set colors {#000 #006 #00B #00F #03F #07F #0BF #0FF #0FB #0F7 \
	    #0F0 #3F0 #7F0 #BF0 #FF0 #FB0 #F70 #F30 #F00}
26
27
28
29
30
31
32
33

34
35
36
37
38
39
40
26
27
28
29
30
31
32

33
34
35
36
37
38
39
40







-
+







  set version "Looking up latest version at $home ..."
  catch {::http::geturl $home/$tcl_platform(platform).date -command CheckV}
}
snack::menuCommand File Mixer... snack::mixerDialog
snack::menuCommand File Quit exit

proc CheckV token {
  set ::version "Your version of Snack was released March 27, 2001. \
  set ::version "Your version of Snack was released March 7, 2002. \
      Latest version released [::http::data $token]."
}

# Title label

pack [frame .t] -pady 5
pack [label .t.l -text "Snack Sound Toolkit Demonstrations"\
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
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







-
-
-
+
+
+
+
+



+
-
-
+
+

-
+

-
-
+
+
+
+
+
+
+
+
+
+
+
+
+







pack [button .f3.b1 -text "Simple" -command {Run MinSect.tcl}] -side left
pack [button .f3.b2 -text "See Code" -command {Browse MinSect.tcl}] -side left
pack [button .f3.b3 -text "Fancy" -command {Run Section.tcl}] -side left
pack [button .f3.b4 -text "See Code" -command {Browse Section.tcl}] -side left
pack [frame  .f4] -pady 2
pack [label  .f4.l -text "Filter examples:"] -side left
pack [button .f4.b1 -text "Channel Map" -command {Run mapChan.tcl}] -side left
pack [button .f4.b3 -text "Echo" -command {Run echo.tcl}] -side left
pack [button .f4.b4 -text "Composite" -command {Run compose.tcl}] -side left
pack [button .f4.b5 -text "Synthesis" -command {Run formant.tcl}] -side left
pack [button .f4.b2 -text "Echo" -command {Run echo.tcl}] -side left
pack [button .f4.b3 -text "Composite" -command {Run compose.tcl}] -side left
pack [button .f4.b4 -text "Generator" -command {Run generator.tcl}] -side left
pack [button .f4.b5 -text "Generator2" -command {Run generator2.tcl}] -side left
pack [button .f4.b6 -text "Notescale" -command {Run notescale.tcl}] -side left
pack [frame  .f5] -pady 2
pack [label  .f5.l -text "Sound tools:"] -side left
pack [button .f5.b1 -text "Simple" -command {Run cool.tcl}] -side left
pack [button .f5.b2 -text "dbrec" -command {Run dbrec.tcl}] -side left
pack [button .f5.b2 -text "record" -command {Run record.tcl}] -side left
pack [button .f5.b3 -text "xs" -command {Run xs.tcl demo}] -side left
pack [button .f5.b3 -text "record" -command {Run record.tcl}] -side left
pack [button .f5.b4 -text "xs" -command {Run xs.tcl demo}] -side left
pack [label  .f5.l2 -text "MP3 player:"] -side left
pack [button .f5.b4 -text "tomAmp" -command {Run tomAmp.tcl}] -side left
pack [button .f5.b5 -text "tomAmp" -command {Run tomAmp.tcl}] -side left
pack [label  .f5.l3 -text "Mixer:"] -side left
pack [button .f5.b5 -text "mixer" -command {Run mixer.tcl}] -side left
pack [label .v -textvar version]
pack [button .f5.b6 -text "mixer" -command {Run mixer.tcl}] -side left
pack [frame  .f6] -pady 2
pack [label  .f6.l -text "Speech toys:"] -side left
pack [button .f6.b1 -text "Synthesis" -command {Run formant.tcl}] -side left
pack [button .f6.b2 -text "Pitch" -command {Run pitch.tcl}] -side left
pack [button .f6.b3 -text "Phonetogram" -command {Run phonetogram.tcl}] -side left
pack [button .f6.b4 -text "Spectrum" -command {Run polarspec.tcl}] -side left
if {$::tcl_platform(platform) == "unix" || \
    $::tcl_platform(platform) == "windows"} {
  pack [label  .f6.l2 -text "Script compiler:"] -side left
  pack [button .f6.b5 -text "wrap" -command {Run wrap.tcl}] -side left
  pack [label .v -textvar version]
}

proc Run {script {demoFlag 0}} {
  set i [interp create]
  load {} Tk $i
  $i eval rename exit dontexit
  interp alias $i exit {} interp delete $i
  if {$demoFlag != 0} {

Changes to snack/demos/tcl/wrap.tcl.

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
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








-
+







-
+







+
-
+







+
-
+








-
+




-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

# This utility creates stand-alone executables from Snack Tcl scripts
# It needs the freewrap tool which can be downloaded from
# http://freewrap.sourceforge.net/
# Edit this file to set the freewrap variable below according to
# your install path.
# your freewrap install path.


pack [label .l1 -text "This utility creates\nstand-alone executables"]
update

# Get the Snack package's directory

package require -exact snack 2.0
package require -exact snack 2.1
set tmp [package ifneeded snack [package provide snack]]
set tmp [lindex [lindex [split $tmp ";"] 0] end]
set snackdir [file dirname $tmp]

switch -glob [string tolower $tcl_platform(platform)] {
 windows {
# Customize freewrap install dir here
# freewrap.exe is included in the Windows binary distribution
  set freewrap E:/freewrap44/freewrap.exe
  set freewrap [file join [pwd] freewrap.exe]
  set tmpdir C:/temp
  regsub -all {\\} $tmpdir / tmpdir
  set wrapdir [file join $tmpdir wrap]
  set appextension .exe
 }
 unix {
# Customize freewrap install dir here
# freewrap executable for Linux-i386 is included in the source distribution
  set freewrap ~/bin/freewrap
  set freewrap [file join [pwd] freewrap]
  set tmpdir /tmp
  set wrapdir [file join $tmpdir wrap]
  set appextension ""
 }
 default {
  error "unknown os $tcl_platform(os)"
 }
}

if {[info exists argv] == 0} { set argv "" }
set mainprog [file rootname [lindex $argv 0]]
if {$mainprog == ""} {
 set mainprog [file rootname [lindex [file split \
	 [tk_getOpenFile -filetypes {{{Tcl scripts} {.tcl}}}]] end]]
 if {$mainprog == ""} exit
  if {$mainprog == ""} return
}

if {[file executable $freewrap] == 0} {
    tk_messageBox -message "This utility requires the freewrap program which is available at http://freewrap.sourceforge.net/. Edit wrap.tcl in order to specify its install path."
 exit
}

62
63
64
65
66
67
68














69
70
71
72
73
74
75
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+







	[list $snackdir/libsnack[info sharedlibextension] \
	$snackdir/snack.tcl $snackdir/pkgIndex.tcl ]] {
 file mkdir $dir
 foreach file $list {
  file copy $file $dir
 }
}

# Copy standard extension packages if they are needed

set f0 [open ${mainprog}.tcl r]
while {[eof $f0] == 0} {
  set line [gets $f0]
  if {[string match {*package require*snackogg*} $line]} {
    file copy $snackdir/libsnackogg[info sharedlibextension] $dir
  }
  if {[string match {*package require*snacksphere*} $line]} {
    file copy $snackdir/libsnacksphere[info sharedlibextension] $dir
  }
}
close $f0

# copy script files to the wrap directory, and insert magic code

set files ${mainprog}.tcl
set files [concat $files [lrange $argv 1 end]]

foreach fn $files {
144
145
146
147
148
149
150

151
160
161
162
163
164
165
166
167
168







+

# Do the actual wrapping

eval exec $freewrap ${mainprog}.tcl $wrapfiles
file copy -force $wrapdir/${mainprog}$appextension $appdir

catch {exec chmod -R 777 $wrapdir}
catch {tk_messageBox -message "Created: ${mainprog}$appextension"}
cd $appdir
exit

Changes to snack/demos/tcl/xs.tcl.

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
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




-
-
-
+
+
+
+
-




















-
+







#!/bin/sh
# the next line restarts using wish \
exec wish8.3 "$0" "$@"

package require -exact snack 2.0
catch {
    package require snacksphere
package require -exact snack 2.1
# Try to load optional file format handlers
catch { package require snacksphere }
catch { package require snackogg }
}
package require http

set debug 0
snack::debug $debug
snack::sound snd -debug $debug
snack::sound cbs -debug $debug

set tcl_precision 7
set f(prog) [info script]
set f(labfile) ""
set f(sndfile) ""
set f(lpath)   ""
set f(header)  ""
set mexhome "~/snack/"
catch {source $mexhome/ipa_tmh.tcl}
set f(ipapath) $mexhome/ipa_xbm
set local 0
if $local {
    set v(labfmt) TIMIT
    set v(smpfmt) WAV
    set v(ashost) datan.speech.kth.se
    set v(ashost) ior.speech.kth.se
} else {
    set v(labfmt) TIMIT
    set v(smpfmt) WAV
    set v(ashost) localhost
}
set labels {}
set undo {}
45
46
47
48
49
50
51
52
53


54
55
56
57
58
59
60
45
46
47
48
49
50
51


52
53
54
55
56
57
58
59
60







-
-
+
+







set v(psfilet) {tmp$N.ps}
set v(psfile)  ""
set v(vchan)   -1
#set v(offset) 0
#set v(zerolabs) 0
set v(startsmp) 0
set v(lastmoved) -1
set v(p_version) 2.0
set v(s_version) 2.0
set v(p_version) 2.1
set v(s_version) 2.1
set v(plugins) {}
set v(scroll) 1
set v(rate) 16000
set v(sfmt) Lin16
set v(chan) 1
set v(topfr) 8000
set v(rp_sock) ""
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
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







+



+
+






+
+



-
-
-
-
-


-
+







set v(contrast) 0
set v(brightness) 0
set v(showspeg) 0
set v(remspegh) 200
set v(remote) 0
set v(asport) 23654
set v(handle) ""
set v(s0) 0

set z(zoomwinh) 200
set z(zoomwinw) 600
set z(zoomwinx) 200
set z(zoomwiny) 200
set z(zoomwavh) 0
set z(zoomwavw) 0
set z(f) 1

set s(sectwinh) 400
set s(sectwinw) 400
set s(sectwinx) 200
set s(sectwiny) 200
set s(secth) 400
set s(sectw) 400
set s(rx) -1
set s(fftlen) 512
set s(anabw)  31.25
set s(ref)    -110.0
set s(range)  110.0
set s(wintype) Hamming

proc SetDefaultVars {} {
    global f v local
    global f v s local

    set v(waveh) 50
    set v(spegh) 0
    set v(scrw) 32767
    set v(pps) 400
    set v(opps) 400
    set v(fftlen) 256
127
128
129
130
131
132
133
134
135


136
137
138
139
140
141
142
127
128
129
130
131
132
133


134
135
136
137
138
139
140
141
142







-
-
+
+







#	set v(browser) "netscape"
	if {$::tcl_platform(os) == "HP-UX"} {
	    option add *font {Helvetica 10 bold}
	} else {
	    option add *font {Helvetica 12 bold}
	}
    } else {
	set v(printcmd)  {C:/gstools/gs5.50/gswin32 "-IC:\gstools\gs5.50;C:\gstools\gs5.50\fonts" -sDEVICE=laserjet -dNOPAUSE $FILE -c quit}
	set v(gvcmd)     {C:/gstools/gsview/gsview32 $FILE}
	set v(printcmd)  {C:/gs/gs6.50/bin/gswin32 "-IC:\gs\gs6.50;C:\gs\gs6.50\fonts" -sDEVICE=laserjet -dNOPAUSE $FILE -c quit}
	set v(gvcmd)     {C:/ghostgum/gsview/gsview32 $FILE}
	set v(psfilecmd) {command.com /c copy _xspr$n.ps $v(psfile)}
	if $local {
#	    set v(pluginfiles) {H:/tcl/mexd/dataplot.plg H:/tcl/mexd/generator.plg H:/tcl/mexd/pitch.plg}
            set v(pluginfiles) {}
	} else {
	    set v(pluginfiles) [glob -nocomplain *.plg]
	}
161
162
163
164
165
166
167
















168
169
170
171
172
173
174
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    set v(remspegh) 200
    set v(linkfile) 0
    set f(skip) 0
    set f(byteOrder) ""
    set f(ipath) ""
    set f(ihttp) "http://www.speech.kth.se/~kare/ex1.wav"
    #"http://www.speech.kth.se/cgi-bin/TransAll?this_is_an_example+am"

    set s(fftlen) 512
    set s(anabw)  31.25
    set s(ref)    -110.0
    set s(range)  110.0
    set s(wintype) Hamming
    set s(atype) FFT
    set s(lpcorder) 20

    if {[info exists snack::snackogg]} {
      set ::ogg(nombr) 128000
      set ::ogg(maxbr) -1
      set ::ogg(minbr) -1
      set ::ogg(com)   ""
      set ::ogg(query) 1
    }
}

SetDefaultVars
catch { source [file join ~ .xsrc] }
catch { source [file join ~ .xsrf] }

snd config -rate $v(rate)
189
190
191
192
193
194
195


196
197
198
199
200
201
202
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220







+
+







set amplify(v) 100.0
set amplify(db) 0

set normalize(f) [snack::filter map 1.0]
set normalize(v) 100.0
set normalize(db) 0
set normalize(allEqual) 1

set remdc(f) [snack::filter iir -numerator "0.99 -0.99" -denominator "1 -0.99"]

set f(spath) $f(ipath)
set f(http) $f(ihttp)
set f(urlToken) ""

if {$v(p_version) != $v(s_version)} {
     set v(msg) "Warning, you have saved settings from an older version of xs!"
298
299
300
301
302
303
304

305
306
307
308
309



310
311
312
313
314
315
316
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338







+





+
+
+







snack::menuCommand Transform Normalize... Normalize
#snack::menuCommand Transform Normalize... Normalize
snack::menuCommand Transform Echo... Echo
snack::menuCommand Transform {Mix Channels...} MixChan
snack::menuCommand Transform Invert Invert
snack::menuCommand Transform Reverse Reverse
snack::menuCommand Transform Silence Silence
snack::menuCommand Transform {Remove DC} RemoveDC

snack::menuPane Tools

snack::menuPane Options 0 ConfigOptionsMenu
snack::menuCommand Options Settings... Settings
if {[info exists snack::snackogg]} {
  snack::menuCommand Options "Ogg Vorbis..." [list OggSettings Close]
}
snack::menuCommand Options Plug-ins... Plugins
snack::menuCascade Options {Label File Format}
snack::menuRadio {Label File Format} TIMIT v(labfmt) TIMIT {Redraw quick}
snack::menuRadio {Label File Format} HTK v(labfmt) HTK {Redraw quick}
snack::menuRadio {Label File Format} WAVES v(labfmt) WAVES {Redraw quick}
snack::menuRadio {Label File Format} MIX v(labfmt) MIX {Redraw quick}
if $local {
657
658
659
660
661
662
663






664
665
666
667
668
669
670













































671
672
673
674
675
676
677
679
680
681
682
683
684
685
686
687
688
689
690
691







692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743







+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    if [catch {open [file join ~ .xsrf] w} out] {
    } else {
	puts $out "set recentFiles \[list $recentFiles\]"
	close $out
    }
}

set extTypes  [list {TIMIT .phn} {MIX .smp.mix} {HTK .lab} {WAVES .lab}]
set loadTypes [list {{MIX Files} {.mix}} {{HTK Label Files} {.lab}} {{TIMIT Label Files} {.phn}} {{TIMIT Label Files} {.wrd}} {{Waves Label Files} {.lab}}]
set loadKeys [list MIX HTK TIMIT WAVES]
set saveTypes {}
set saveKeys  {}

if [info exists snack::snacksphere] {
    snack::addExtTypes {{SPHERE .sph} {SPHERE .wav} {TIMIT .phn} {MIX .smp.mix} {HTK .lab} {WAVES .lab}}
    snack::addLoadTypes {{{SPHERE Files} {.sph}} {{SPHERE Files} {.wav}} {{MIX Files} {.mix}} {{HTK Label Files} {.lab}} {{TIMIT Label Files} {.phn}} {{TIMIT Label Files} {.wrd}} {{Waves Label Files} {.lab}}} {SPHERE SPHERE MIX HTK TIMIT WAVES}
} else {
    snack::addExtTypes {{TIMIT .phn} {MIX .smp.mix} {HTK .lab} {WAVES .lab}}
    snack::addLoadTypes {{{MIX Files} {.mix}} {{HTK Label Files} {.lab}} {{TIMIT Label Files} {.phn}} {{TIMIT Label Files} {.wrd}} {{Waves Label Files} {.lab}}} {MIX HTK TIMIT WAVES}
}
if {[info exists snack::snacksphere]} {
    lappend extTypes {SPHERE .sph} {SPHERE .wav}
    lappend loadTypes {{SPHERE Files} {.sph}} {{SPHERE Files} {.wav}}
    lappend loadKeys SPHERE SPHERE
}
if {[info exists snack::snackogg]} {
  lappend extTypes  {OGG .ogg}
  lappend loadTypes {{Ogg Vorbis Files} {.ogg}}
  lappend loadKeys  OGG
  lappend saveTypes {{Ogg Vorbis Files} {.ogg}}
  lappend saveKeys  OGG
  
  proc OggSettings {text} {
    set w .ogg
    catch {destroy $w}
    toplevel $w
    wm title $w "Ogg Vorbis Settings"

    pack [frame $w.f1] -anchor w
    pack [label $w.f1.l -text "Nominal bitrate:" -widt 16 -anchor w] -side left
    pack [entry $w.f1.e -textvar ::ogg(nombr) -wi 7] -side left

    pack [frame $w.f2] -anchor w
    pack [label $w.f2.l -text "Max bitrate:" -width 16 -anchor w] -side left
    pack [entry $w.f2.e -textvar ::ogg(maxbr) -wi 7] -side left

    pack [frame $w.f3] -anchor w
    pack [label $w.f3.l -text "Min bitrate:" -width 16 -anchor w] -side left
    pack [entry $w.f3.e -textvar ::ogg(minbr) -wi 7] -side left
    
    pack [frame $w.f4] -anchor w
    pack [label $w.f4.l -text "Comment:" -width 16 -anchor w] -side left
    pack [entry $w.f4.e -textvar ::ogg(com) -wi 40] -side left

    pack [frame $w.f5] -anchor w
    pack [checkbutton $w.f5.b -text "Query settings before saving" \
	-variable ::ogg(query) -anchor w] -side left

    pack [frame $w.fb] -side bottom -fill x
    pack [button $w.fb.cb -text $text -command "destroy $w"] -side top
  }
}

snack::addExtTypes $extTypes
snack::addLoadTypes $loadTypes $loadKeys

proc GetOpenFileName {} {
    global f v

    if {$v(smpchanged) || $v(labchanged)} {
	if {[tk_messageBox -message "You have unsaved changes.\n Do you \
		really want to close?" -type yesno \
697
698
699
700
701
702
703
704


705
706
707


708
709
710


711
712
713


714
715
716


717
718


719
720
721
722
723
724
725
763
764
765
766
767
768
769

770
771
772
773

774
775
776
777

778
779
780
781

782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799







-
+
+


-
+
+


-
+
+


-
+
+



+
+


+
+








proc GetSaveFileName {title} {
    global f v labels

    if {$labels != {} && [string compare $title "Save sample file"] != 0} {  
	switch $v(labfmt) {
	    MIX {
		snack::addSaveTypes {{{MIX Files} {.mix}}} {MIX}
	      lappend ::saveTypes {{MIX Files} {.mix}}
	      lappend ::saveKeys  MIX
	    }
	    HTK {
		snack::addSaveTypes {{{HTK Label Files} {.lab}}} {HTK}
	      lappend ::saveTypes {{HTK Label Files} {.lab}}
	      lappend ::saveKeys  HTK
	    }
	    TIMIT {
		snack::addSaveTypes {{{TIMIT Label Files} {.phn}} {{TIMIT Label Files} {.wrd}}} {TIMIT}
	      lappend ::saveTypes {{TIMIT Label Files} {.phn}} {{TIMIT Label Files} {.wrd}}
	      lappend ::saveKeys  TIMIT
	    }
	    WAVES {
		snack::addSaveTypes {{{Waves Label Files} {.lab}}} {WAVES}
	      lappend ::saveTypes {{Waves Label Files} {.lab}}
	      lappend ::saveKeys  WAVES
	    }
	    default
	}
	snack::addSaveTypes $::saveTypes $::saveKeys

	set gotfn [snack::getSaveFile -initialdir $f(lpath) -initialfile $f(labfile) -format $v(labfmt) -title $title]
 } else {
	snack::addSaveTypes $::saveTypes $::saveKeys

	set gotfn [snack::getSaveFile -initialdir $f(spath) -initialfile $f(sndfile) -format $v(smpfmt) -title $title]
    }
#    set tmp [string trimright $f(lpath) /].
#    if {[regexp $tmp $gotfn] == 1 && $tmp != "."} {
#	return ""
#    }
    update
751
752
753
754
755
756
757
758

759
760
761
762
763
764




















765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787



















788
789
790
791
792
793
794
825
826
827
828
829
830
831

832
833





834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854






















855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880







-
+

-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







	if {$fn != ""} {
	    SaveFile $fn
	}
    }
}

proc SaveFile {{fn ""}} {
    global f v labels
  global f v labels

    SetCursor watch
    set strip_fn [lindex [file split [file rootname $fn]] end]
    set ext  [file extension $fn]
    if [string match macintosh $::tcl_platform(platform)] {
	set path [file dirname $fn]:
  SetCursor watch
  set strip_fn [lindex [file split [file rootname $fn]] end]
  set ext  [file extension $fn]
  if [string match macintosh $::tcl_platform(platform)] {
    set path [file dirname $fn]:
  } else {
    set path [file dirname $fn]/
  }
  if {$path == "./"} { set path ""}
  if {![IsLabelFile $fn]} {
    if {[info exists snack::snackogg]} {
      if {$::ogg(query) && [string match -nocase .ogg $ext]} {
	OggSettings Continue
	tkwait window .ogg
      }
      if [catch {snd write $fn -progress snack::progressCallback \
	  -nominalbitrate $::ogg(nombr) -maxbitrate $::ogg(maxbr) \
	  -minbitrate $::ogg(minbr) -comment $::ogg(com)} msg] {
	SetMsg "Save cancelled: $msg"
      }
    } else {
	set path [file dirname $fn]/
    }
    if {$path == "./"} { set path ""}
    if ![IsLabelFile $fn] {
	if [catch {snd write $fn -progress snack::progressCallback} msg] {
	    SetMsg "Save cancelled: $msg"
	}
	if {$v(linkfile)} {
	    snd configure -file $fn
	}
	set v(smpchanged) 0
	wm title . "xs: $fn"
	set f(spath) $path
	set f(sndfile) $strip_fn$ext
    } elseif {$labels != {}} {
	SaveLabelFile $labels $fn
	set v(labchanged) 0
	wm title . "xs: $f(spath)$f(sndfile) - $fn"
	set f(lpath) $path
	set f(labfile) $strip_fn$ext
    }
    SetCursor ""
      if [catch {snd write $fn -progress snack::progressCallback} msg] {
	SetMsg "Save cancelled: $msg"
      }
    }
    if {$v(linkfile)} {
	snd configure -file $fn
    }
    set v(smpchanged) 0
    wm title . "xs: $fn"
    set f(spath) $path
    set f(sndfile) $strip_fn$ext
  } elseif {$labels != {}} {
    SaveLabelFile $labels $fn
    set v(labchanged) 0
    wm title . "xs: $f(spath)$f(sndfile) - $fn"
    set f(lpath) $path
    set f(labfile) $strip_fn$ext
  }
  SetCursor ""
}

proc IsLabelFile {fn} {
    set ext [file extension $fn]
    if {$ext == ".lab"} { return 1 }
    if {$ext == ".mix"} { return 1 }
    if {$ext == ".phn"} { return 1 }
923
924
925
926
927
928
929
930

931
932
933
934
935
936
937
1009
1010
1011
1012
1013
1014
1015

1016
1017
1018
1019
1020
1021
1022
1023







-
+







    if {($v(autoload) == 1) || ($type == "smp")} {
	$c delete wave speg
	.of.c delete overwave
	catch {.sect.c delete sect}
	StopPlay

	set f(byteOrder) [snd cget -byteorder]
	set tmps [snack::sound]
	set tmps [snack::sound -debug $::debug]
	set ffmt [$tmps read $f(spath)$f(sndfile) -end 1 -guessproperties 1]
	if {$ffmt == "RAW"} {
	    set v(rate)      [$tmps cget -rate]
	    set v(sfmt)      [$tmps cget -encoding]
	    set v(chan)      [$tmps cget -channels]
	    set f(byteOrder) [$tmps cget -byteorder]
	    if {[InterpretRawDialog] == "cancel"} {
1026
1027
1028
1029
1030
1031
1032
1033


1034
1035
1036
1037
1038
1039
1040
1112
1113
1114
1115
1116
1117
1118

1119
1120
1121
1122
1123
1124
1125
1126
1127







-
+
+







    pack [label $w.q.f4.l -text "Byte Order"]
    pack [radiobutton $w.q.f4.ri -text "Little Endian\n(Intel)" \
	    -value littleEndian -var ::f(byteOrder)] -anchor w
    pack [radiobutton $w.q.f4.rm -text "Big Endian\n(Motorola)" \
	    -value bigEndian -var ::f(byteOrder)] -anchor w
    pack [label $w.q.f4.l2 -text "\nRead Offset (bytes)"]
    pack [entry $w.q.f4.e -textvar f(skip) -wi 6]
    snack::makeDialogBox $w -title "Interpret Raw File As" -type okcancel
    snack::makeDialogBox $w -title "Interpret Raw File As" -type okcancel \
	-default ok
}

proc Link2File {} {
    global f v

    StopPlay
    if {$v(smpchanged)} {
1091
1092
1093
1094
1095
1096
1097

1098
1099
1100
1101
1102
1103
1104
1105
1106

1107
1108
1109
1110
1111
1112
1113
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202







+









+







	snack::menuEntryOff Transform Amplify...
	snack::menuEntryOff Transform Normalize...
	snack::menuEntryOff Transform Echo...
	snack::menuEntryOff Transform {Mix Channels...}
	snack::menuEntryOff Transform Invert
	snack::menuEntryOff Transform Reverse
	snack::menuEntryOff Transform Silence
	snack::menuEntryOff Transform {Remove DC}
    } else {
	snack::menuEntryOn Transform Conversions
	snack::menuEntryOn Transform Amplify...
	snack::menuEntryOn Transform Normalize...
	snack::menuEntryOn Transform Echo...
	snack::menuEntryOn Transform {Mix Channels...}
	snack::menuEntryOn Transform Invert
	snack::menuEntryOn Transform Reverse
	snack::menuEntryOn Transform Silence
	snack::menuEntryOn Transform {Remove DC}
    }
    if {[snd cget -channels] == 1} {
	snack::menuEntryOff Transform {Mix Channels...}
    }
}

proc ConfigOptionsMenu {} {
1462
1463
1464
1465
1466
1467
1468

1469
1470
1471
1472
1473
1474
1475
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565







+







	return
    }

    set v(undoc) "snd reverse -start $start -end $end"
    set v(redoc) "snd reverse -start $start -end $end"
    set v(smpchanged) 1
    .tb.undo config -state normal
    Redraw
}

proc Invert {} {
    global v filt

    if {[Marker2Sample m1] == [Marker2Sample m2]} MarkAll
    set start [Marker2Sample m1]
1486
1487
1488
1489
1490
1491
1492

1493
1494
1495
1496
1497
1498
1499
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590







+







	return
    }

    set v(undoc) "snd swap cbs"
    set v(redoc) "snd swap cbs"
    set v(smpchanged) 1
    .tb.undo config -state normal
    Redraw
}

proc Silence {} {
    global v filt

    set start [Marker2Sample m1]
    set end   [Marker2Sample m2]
1510
1511
1512
1513
1514
1515
1516

























1517
1518
1519
1520
1521
1522
1523
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







	return
    }

    set v(undoc) "snd swap cbs"
    set v(redoc) "snd swap cbs"
    set v(smpchanged) 1
    .tb.undo config -state normal
    Redraw
}

proc RemoveDC {} {
    global v remdc

    if {[Marker2Sample m1] == [Marker2Sample m2]} MarkAll
    set start [Marker2Sample m1]
    set end   [Marker2Sample m2]
    if {$start == $end} return
    SetMsg "Removing DC for range: $start $end"

    cbs copy snd
    if [catch {snd filter $remdc(f) -start $start -end $end \
	    -progress snack::progressCallback -continuedrain 0}] {
	SetMsg "Remove DC cancelled"
	snd copy cbs
	return
    }

    set v(undoc) "snd swap cbs"
    set v(redoc) "snd swap cbs"
    set v(smpchanged) 1
    .tb.undo config -state normal
    Redraw
}

proc ConfAmplify {flag} {
    global amplify

    set w .amp
    if {$amplify(db) == 1} {
1557
1558
1559
1560
1561
1562
1563

1564
1565
1566
1567
1568
1569
1570
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687







+







	return
    }

    set v(undoc) "snd swap cbs"
    set v(redoc) "snd swap cbs"
    set v(smpchanged) 1
    .tb.undo config -state normal
    Redraw
}

proc Amplify {} {
    global amplify

    if {[Marker2Sample m1] == [Marker2Sample m2]} MarkAll
    set w .amp
1614
1615
1616
1617
1618
1619
1620
1621

1622
1623
1624
1625
1626
1627
1628


1629
1630
1631
1632
1633
1634
1635
1731
1732
1733
1734
1735
1736
1737

1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754







-
+







+
+







proc DoNormalize {} {
    global v normalize

    set start [Marker2Sample m1]
    set end   [Marker2Sample m2]
    if {$start == $end} return
    SetMsg "Normalizing range: $start $end"

  
    if {$normalize(db) == 1} {
	set tmp [expr {pow(10,$normalize(v)/20.0)}]
    } else {
	set tmp [expr {$normalize(v) / 100.0}]
    }
    if {[string match [snd cget -encoding] Lin8]} {
	set smax 255.0
    } elseif {[string match [snd cget -encoding] Lin24]} {
        set smax 8388608.0
    } else {
	set smax 32767.0
    }
    for {set c 0} {$c < [snd cget -channels]} {incr c} {
	if {$normalize(allEqual)} {
         set max [snd max -start $start -end $end]
         set min [snd min -start $start -end $end]
1665
1666
1667
1668
1669
1670
1671

1672
1673
1674
1675
1676
1677
1678
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798







+







	return
    }

    set v(undoc) "snd swap cbs"
    set v(redoc) "snd swap cbs"
    set v(smpchanged) 1
    .tb.undo config -state normal
    Redraw
}

proc Normalize {} {
    global normalize

    if {[Marker2Sample m1] == [Marker2Sample m2]} MarkAll
    set w .norm
1731
1732
1733
1734
1735
1736
1737

1738
1739
1740
1741
1742
1743
1744
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865







+







	return
    }

    set v(undoc) "snd swap cbs"
    set v(redoc) "snd swap cbs"
    set v(smpchanged) 1
    .tb.undo config -state normal
    Redraw
}

proc PlayEcho {} {
    global echo

    set start [Marker2Sample m1]
    set end   [Marker2Sample m2]
1878
1879
1880
1881
1882
1883
1884

1885
1886
1887
1888
1889
1890
1891
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013







+







	return
    }

    set v(undoc) "snd swap cbs"
    set v(redoc) "snd swap cbs"
    set v(smpchanged) 1
    .tb.undo config -state normal
    Redraw
}

proc PlayMix {} {
    global mix

    set start [Marker2Sample m1]
    set end   [Marker2Sample m2]
2021
2022
2023
2024
2025
2026
2027
2028

2029
2030
2031
2032
2033
2034
2035
2143
2144
2145
2146
2147
2148
2149

2150
2151
2152
2153
2154
2155
2156
2157







-
+







    global c v

    set f [Time2Coord [expr double($a / $v(width))]]
    eval $c xview moveto $f
}

proc Redraw {args} {
    global c labels f v debug
    global c labels f v

    SetCursor watch
    set length [snd length]
    if {$args != "quick"} {
	$c delete obj
	$c config -bg $v(bg)
	.cf.fyc.yc config -bg $v(bg)
2055
2056
2057
2058
2059
2060
2061
2062

2063
2064
2065
2066
2067
2068
2069
2070

2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084



2085
2086
2087
2088
2089
2090
2091
2092
2093

2094
2095
2096
2097
2098
2099
2100
2177
2178
2179
2180
2181
2182
2183

2184
2185
2186
2187
2188
2189
2190
2191

2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217

2218
2219
2220
2221
2222
2223
2224
2225







-
+







-
+














+
+
+








-
+







	.cf.fyc.yc delete axis
	if {$v(waveh) > 0} {
	    if {$v(linkfile) && $f(sndfile) != ""} {
		snack::deleteInvalidShapeFile [file tail $f(spath)$f(sndfile)]
		$c create waveform 0 0 -sound snd -height $v(waveh) \
			-pixels $v(pps) -tags [list obj wave] \
			-start $v(startsmp) -end $v(endsmp) \
			-channel $v(vchan) -debug $debug -fill $v(fg) \
			-channel $v(vchan) -debug $::debug -fill $v(fg) \
	-shapefile [file rootname [file tail $f(spath)$f(sndfile)]].shape\
			-progress snack::progressCallback
		snack::makeShapeFileDeleteable [file tail $f(spath)$f(sndfile)]
	    } else {
		$c create waveform 0 0 -sound snd -height $v(waveh) \
			-pixels $v(pps) -tags [list obj wave] \
			-start $v(startsmp) -end $v(endsmp) \
			-channel $v(vchan) -debug $debug -fill $v(fg)
			-channel $v(vchan) -debug $::debug -fill $v(fg)
	    }
	    $c lower wave
	    .cf.fyc.yc create text $v(yaxisw) 2 -text [snd max]\
		    -font $v(sfont) -anchor ne -tags axis -fill $v(fg)
	    .cf.fyc.yc create text $v(yaxisw) $v(waveh) -text [snd min]\
		    -font $v(sfont) -anchor se -tags axis -fill $v(fg)
	    .cf.fyc.yc create line 0 [expr $v(waveh)+0] $v(yaxisw) \
		    [expr $v(waveh)+0] -tags axis -fill $v(fg)  
	}
	if {$v(topfr) > [expr $v(rate)/2]} {
	    set v(topfr) [expr $v(rate)/2]
	}
	if {$v(spegh) > 0} {
	    set v(winlen) [expr int($v(rate) / $v(anabw))]
	    if {$v(winlen) > $v(fftlen)} {
	      set v(winlen) $v(fftlen)
	    }
	    $c create spectrogram 0 $v(waveh) -sound snd -fftlen $v(fftlen) \
		    -winlen $v(winlen) -height $v(spegh) -pixels $v(pps) \
		    -preemph $v(preemph) -topfr $v(topfr) -tags [list obj speg] \
		    -start $v(startsmp) -end $v(endsmp)\
		    -contrast $v(contrast) -brightness $v(brightness)\
		    -gridtspacing $v(gridtspacing) \
		    -gridfspacing $v(gridfspacing) -channel $v(vchan) \
		    -colormap $v($v(cmap)) -gridcol $v(gridcolor) \
		    -progress snack::progressCallback -debug $debug
		    -progress snack::progressCallback -debug $::debug
	    $c lower speg
	    snack::frequencyAxis .cf.fyc.yc 0 $v(waveh) $v(yaxisw) $v(spegh)\
		    -topfrequency $v(topfr) -tags axis -fill $v(fg)\
		    -font $v(sfont)
	    .cf.fyc.yc create line 0 [expr $v(spegh) + $v(waveh)+0] \
		    $v(yaxisw) [expr $v(spegh) + $v(waveh)+0] -tags axis\
		    -fill $v(fg)
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288







2289



2290
2291
2292



2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311

2312
2313
2314
2315
2316
2317
2318
2401
2402
2403
2404
2405
2406
2407






2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418



2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439

2440
2441
2442
2443
2444
2445
2446
2447







-
-
-
-
-
-
+
+
+
+
+
+
+

+
+
+
-
-
-
+
+
+


















-
+







    set v(startsmp) [expr int ([lindex [.of.xscroll get] 0] * [snd length])]
    set v(endsmp)   [expr int ([lindex [.of.xscroll get] 1] * [snd length])]
    $c xview moveto 0
    Redraw
}

proc DrawOverAxis {} {
    global v

    set totw [winfo width .]
    set scrh [winfo height .of.xscroll]
    set width [expr $totw - 2 * $scrh]
    set length [snd length -unit seconds]
  global v
  
  set totw [winfo width .]
  set scrh [winfo height .of.xscroll]
  set width [expr $totw - 2 * $scrh]
  set length [snd length -unit seconds]
  if {$length > 0} {
    set v(opps) [expr $width/$length]
  } else {
    set v(opps) 400
  }
    .of.c delete overaxis
    snack::timeAxis .of.c $scrh 20 $width 11 $v(opps) -tags overaxis \
	    -fill $v(fg)
  .of.c delete overaxis
  snack::timeAxis .of.c $scrh 20 $width 11 $v(opps) -tags overaxis \
      -fill $v(fg)
}

proc OverPlay {x} {
    global v
    
    set start [expr int($v(rate)*(($x - [winfo height .of.xscroll]) * 1000 / $v(opps)))]
    set end   [snd length]
    Stop snd
    if {$start < 0} { set start 0 }
    set v(s0) $start
    set v(s1) $end
    Play snd $start $end
    .of.c create poly -1 -1 -1 -1 -1 -1 -fill red -tags playmark
    after cancel PutPlayMarker
    after 50 PutPlayMarker
}

proc Reconf {} {
    global c v f debug
    global c v f

    set dox 0
    set doy 0
    if {[$c xview] == "0 1"} { set dox 1 }
    if {[$c yview] == "0 1"} { set doy 1 }

    if {$dox} {
2332
2333
2334
2335
2336
2337
2338
2339

2340
2341
2342
2343

2344
2345
2346
2347
2348
2349
2350
2461
2462
2463
2464
2465
2466
2467

2468
2469
2470
2471

2472
2473
2474
2475
2476
2477
2478
2479







-
+



-
+







    set ww [.of.c itemcget overwave -width]
    set v(scrh) [winfo height .of.xscroll]
    set totw [expr [winfo width .] - 2 * $v(scrh)]
    if {$ww != $totw && ![catch {pack info .of}]} {
	.of.c delete overwave
        if {$v(linkfile) && $f(sndfile) != ""} {
	    .of.c create waveform $v(scrh) 0 -sound snd -height 20 \
		    -width $totw -tags overwave -fill $v(fg) -debug $debug \
		    -width $totw -tags overwave -fill $v(fg) -debug $::debug \
	    -shapefile [file rootname [file tail $f(spath)$f(sndfile)]].shape
	} else {
	    .of.c create waveform $v(scrh) 0 -sound snd -height 20 \
		    -width $totw -tags overwave -fill $v(fg) -debug $debug
		    -width $totw -tags overwave -fill $v(fg) -debug $::debug
	}
	.of.c create rectangle -1 -1 -1 -1 -tags mark -fill yellow -stipple gray25
    }
    if {[snd length] > 0} DrawOverAxis
#    if {$::tcl_platform(platform) == "unix"} {
#	if {$v(propflag) > 1} { pack propagate . 0 }
#    }
2646
2647
2648
2649
2650
2651
2652
2653

2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665

2666
2667
2668
2669
2670
2671

2672
2673
2674
2675
2676
2677
2678
2775
2776
2777
2778
2779
2780
2781

2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793

2794
2795
2796
2797
2798
2799

2800
2801
2802
2803
2804
2805
2806
2807







-
+











-
+





-
+







    } else {
	.tb.rec config -state disabled
    }

}

proc Record {} {
    global c v rec debug
    global c v rec

    StopPlay
    set v(smpchanged) 1
    if [winfo exist .of] { pack forget .of }
    $c delete obj
    .of.c delete overwave
    set width [winfo width $c]
    $c xview moveto 0
    if {$v(waveh) > 0} {
	$c create waveform 0 0 -sound snd -height $v(waveh) -pixels $v(pps) \
		-width $width -tags [list obj recwave] -channel $v(vchan) \
		-debug $debug -fill red
		-debug $::debug -fill red
    }
    if {$v(spegh) > 0} {
	$c create spectrogram 0 $v(waveh) -sound snd -height $v(spegh) \
		-pixels $v(pps) \
		-width $width -tags [list obj recwave] -channel $v(vchan) \
		-colormap $v($v(cmap)) -debug $debug
		-colormap $v($v(cmap)) -debug $::debug
    }
    if {$v(linkfile)} {
	catch {file delete -force _xs[pid].wav}
	snd configure -file _xs[pid].wav
    }
    snd record
    set v(activerec) 1
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800

2801
2802
2803
2804
2805

2806
2807
2808
2809
2810
2811
2812
2813
2920
2921
2922
2923
2924
2925
2926



2927
2928
2929
2930


2931

2932
2933
2934
2935
2936
2937
2938







-
-
-
+



-
-
+
-







}

proc Undo {} {
    global c v labels undo

    if {[cbs length] != 0} {
	eval $v(undoc)
	set tmp $v(undoc)
	set v(undoc) $v(redoc)
	set v(redoc) $tmp
        foreach {v(undoc) v(redoc)} [list $v(redoc) $v(undoc)] break
	DrawOverAxis
	Redraw
    } else {
	set tmp $labels
	set labels $undo
        foreach {labels undo} [list $undo $labels] break
	set undo $tmp
	Redraw quick
    }
    SetMsg ""
}

proc SetUndo {l} {
    global undo
3522
3523
3524
3525
3526
3527
3528


3529

3530
3531
3532
3533
3534
3535
3536
3647
3648
3649
3650
3651
3652
3653
3654
3655

3656
3657
3658
3659
3660
3661
3662
3663







+
+
-
+







	if {$xc > $v(width)} { set xc $v(width) }

	set t [Coord2Time $xc]
    } else {
	set xc [Time2Coord $x]
	set t $x
    }
    if {$t >= [snd length]} {
      set t [expr {[snd length]-1}]

    }
    $c itemconf $m -tags [list mark $t $m]
    $c coords $m $xc 0 $xc $v(toth)

    if {$m == "m1"} {
	set tm2 [Marker2Time m2]
	if {$t > $tm2} {
	    $c itemconf m2 -tags [list mark $tm2 m3]
3656
3657
3658
3659
3660
3661
3662

3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674


3675
3676

3677
3678

3679
3680
3681
3682
3683




3684
3685
3686














3687
3688
3689
3690
3691
3692
3693
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800


3801
3802
3803

3804
3805

3806
3807




3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835







+










-
-
+
+

-
+

-
+

-
-
-
-
+
+
+
+



+
+
+
+
+
+
+
+
+
+
+
+
+
+








proc OpenSectWindow {} {
    global s v

    catch {destroy .sect}
    toplevel .sect -width $s(sectwinw) -height $s(sectwinh)
    wm title .sect "Spectrum section plot"
    wm geometry .sect +$s(sectwinx)+$s(sectwiny)
    pack propagate .sect 0

    set s(ostart) ""

    pack [frame .sect.f] -side bottom -fill x
    label .sect.f.lab -width 1 -relief sunken -bd 1 -anchor w
    pack .sect.f.lab -side left -expand yes -fill x
    pack [button .sect.f.exitB -text Close -command {destroy .sect}] -side left
    pack [canvas .sect.c -closeenough 5 -cursor draft_small -bg $v(bg)] -fill both -expand true

    pack [frame .sect.f2]
    pack [label .sect.f2.l1 -text "FFT points:" -anchor w] -side left
    pack [frame .sect.f1]
    label .sect.f1.l1 -text "FFT points:" -anchor w
#    pack [entry .sect.f2.e1 -textvar s(fftlen) -wi 6] -side left
    tk_optionMenu .sect.f2.cm1 s(fftlen) 64 128 256 512 1024 2048 4096 8192 16384
    tk_optionMenu .sect.f1.m1 s(fftlen) 64 128 256 512 1024 2048 4096 8192 16384
    for {set n 0} {$n < 7} {incr n} {
	.sect.f2.cm1.menu entryconfigure $n -command DrawSect
      .sect.f1.m1.menu entryconfigure $n -command DrawSect
    }

    tk_optionMenu .sect.f2.cm2 s(wintype) \
	 Hamming Hanning Bartlett Blackman Rectangle
    pack .sect.f2.cm1 .sect.f2.cm2 -side left
    label .sect.f1.l2 -text "Window:"
    tk_optionMenu .sect.f1.m2 s(wintype) \
	Hamming Hanning Bartlett Blackman Rectangle
    pack .sect.f1.l1 .sect.f1.m1 .sect.f1.l2 .sect.f1.m2 -side left
#    pack [label .sect.f2.l2 -text "Preemphasis:" -anchor w] -side left
#    pack [entry .sect.f2.e2 -textvar s(ref) -wi 6] -side left

    pack [frame .sect.f2]
    label .sect.f2.l1 -text "Analysis:"
    tk_optionMenu .sect.f2.m1 s(atype) FFT LPC
    .sect.f2.m1.menu entryconfigure 0 -command [list LPCcontrols disabled]
    .sect.f2.m1.menu entryconfigure 1 -command [list LPCcontrols normal]
    label .sect.f2.l2 -text "Order:"
    entry .sect.f2.e -textvariable s(lpcorder) -width 3
    scale .sect.f2.s -variable s(lpcorder) -from 1 -to 40 -orient horiz \
	-length 80 -show no
    bind .sect.f2.s <Button1-Motion> DrawSect
    pack .sect.f2.l1 .sect.f2.m1 .sect.f2.l2 .sect.f2.e .sect.f2.s -side left
    if {$s(atype) != "LPC"} { LPCcontrols disabled }
    if {$s(lpcorder) < 1} { set s(lpcorder) 20 }

    pack [frame .sect.f3]
    pack [label .sect.f3.l2 -text "Reference:" -anchor w] -side left
    pack [entry .sect.f3.e2 -textvar s(ref) -wi 6] -side left
    pack [label .sect.f3.u1 -text "dB" -anchor w] -side left
    pack [label .sect.f3.l3 -text "Range:" -anchor w] -side left
    pack [entry .sect.f3.e3 -textvar s(range) -wi 5] -side left
    pack [label .sect.f3.u2 -text "dBfs" -anchor w] -side left
3707
3708
3709
3710
3711
3712
3713
3714





3715
3716

3717
3718
3719
3720
3721


3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740


3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751


3752
3753
3754
3755
3756
3757
3758
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862

3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888

3889
3890
3891
3892

3893
3894
3895
3896
3897
3898


3899
3900
3901
3902
3903
3904
3905
3906
3907








+
+
+
+
+

-
+





+
+


















-
+
+


-






-
-
+
+







    bind .sect <Configure> DrawSect
    bind .sect <Any-Key> DrawSect
    bind .sect.c <ButtonPress-1>  { set s(rx) %x; set s(ry) %y ;.sect.c coords relmark 0 0 0 0;.sect.c coords df -10 -10;.sect.c coords db -10 -10}
    bind .sect.c <ButtonRelease-1>  { set s(rx) -1 }
    bind .sect.c <Motion>  {DrawSectMarks %x %y}
    bind .sect.c <Leave>  {.sect.c coords sx -1 -1 -1 -1;.sect.c coords sy -1 -1 -1 -1}
}

proc LPCcontrols {state} {
  .sect.f2.e configure -state $state
  .sect.f2.s configure -state $state
}

proc DrawSect {} {
    global c s v debug
    global c s v

    if [winfo exists .sect] {
	set geom [lindex [split [wm geometry .sect] +] 0]
	set s(sectwinw) [lindex [split $geom x] 0]
	set s(sectwinh) [lindex [split $geom x] 1]
        set s(sectwinx) [lindex [split [wm geometry .sect] +] 1]
        set s(sectwiny) [lindex [split [wm geometry .sect] +] 2]
	set s(sectw) [expr [winfo width .sect.c] - 25]
	set s(secth) [expr [winfo height .sect.c] - 20]
	set s(sectcw) [winfo width .sect.c]
	set s(sectch) [winfo height .sect.c]

	set s(start) [Marker2Sample m1]
	set s(end)   [Marker2Sample m2]
	if {$s(start) == $s(end)} { set s(start) [expr $s(end) - 1]}
	.sect.c delete sect
        set s(top) [expr int(($s(ref) + $s(range)) / 10.0)]
        set s(bot) [expr int($s(ref) / 10.0 )]

catch {
	if {$s(ostart) != ""} {
	    .sect.c create section 25 0 -sound snd -height $s(secth)\
		    -width $s(sectw) -maxvalue [expr 10.0*$s(top)] \
		    -minvalue [expr 10.0*$s(bot)] \
		    -start $s(ostart) -end $s(oend) -tags sect \
		    -fftlen $s(fftlen) \
		    -fftlen $s(fftlen) -analysistype $s(atype) \
		    -lpcorder $s(lpcorder) \
		    -winlen $s(fftlen) -channel $v(vchan) -fill red \
		    -topfr $v(topfr) -windowtype $s(wintype)

	}
	.sect.c create section 25 0 -sound snd -height $s(secth) \
		-width $s(sectw) -maxvalue [expr 10.0*$s(top)] \
		-minval [expr 10.0*$s(bot)] \
		-start $s(start) -end $s(end) -tags sect -fftlen $s(fftlen) \
		-winlen $s(fftlen) -channel $v(vchan) -frame 1 \
		-debug $debug -fill $v(fg) \
		-topfr $v(topfr) -windowtype $s(wintype)
		-debug $::debug -fill $v(fg) -analysistype $s(atype) \
		-lpcorder $s(lpcorder) -topfr $v(topfr) -windowtype $s(wintype)
    }
	.sect.c create text -10 -10 -text df: -font $v(sfont) -tags df \
		-fill blue
	.sect.c create text -10 -10 -text "0 db" -font $v(sfont) -tags db \
		-fill red
	set pps [expr int(double($s(sectw))/($v(topfr)/1000.0) + .5)]
	snack::timeAxis .sect.c 25 $s(secth) $s(sectw) 20 $pps \
3779
3780
3781
3782
3783
3784
3785
3786


3787
3788
3789
3790
3791
3792
3793
3928
3929
3930
3931
3932
3933
3934

3935
3936
3937
3938
3939
3940
3941
3942
3943







-
+
+







    set s(start) [Marker2Sample m1]
    set s(end)   [Marker2Sample m2]

    if {$s(start) == $s(end)} { set s(start) [expr $s(end) - 1]}

    set ps [snd dBPowerSpectrum -start $s(start) -end $s(end) \
	    -fftlen $s(fftlen) -windowlen $s(fftlen) -channel $v(vchan) \
	    -windowtype $s(wintype)]
	    -windowtype $s(wintype) -analysistype $s(atype) \
	    -lpcorder $s(lpcorder)]

    set file [tk_getSaveFile -title "Export spectral data" -initialfile spectrum.txt]
    if {$file == ""} return
    if {[catch {open $file w} out]} {
	return $out
    } else {
	set df [expr {([snd cget -rate] / 2.0) / $s(fftlen)}]
3857
3858
3859
3860
3861
3862
3863

3864
3865
3866
3867
3868
3869
3870
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021







+







proc OpenZoomWindow {} {
    global z v

    catch {destroy .zoom}
    catch {destroy .zmenu}
    toplevel .zoom -width $z(zoomwinw) -height $z(zoomwinh)
    wm title .zoom "Zoom view"
    wm geometry .zoom +$z(zoomwinx)+$z(zoomwiny)
    pack propagate .zoom 0

    frame .zoom.f
    label .zoom.f.lab -text "Press right mouse button for menu" -width 1 -relief sunken -bd 1 -anchor w
    pack .zoom.f.lab -side left -expand yes -fill x
    pack [button .zoom.f.xzoomB -text X-zoom -command {DrawZoom 1}] -side left
    pack [button .zoom.f.yizoomB -text "Y-zoom in" -command {DrawZoom 2}] -side left
3892
3893
3894
3895
3896
3897
3898


3899
3900
3901
3902
3903
3904
3905
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058







+
+







proc DrawZoom {factor} {
    global z v f

    if [winfo exists .zoom] {
	set geom [lindex [split [wm geometry .zoom] +] 0]
	set z(zoomwinw) [lindex [split $geom x] 0]
	set z(zoomwinh) [lindex [split $geom x] 1]
        set z(zoomwinx) [lindex [split [wm geometry .zoom] +] 1]
        set z(zoomwiny) [lindex [split [wm geometry .zoom] +] 2]
	set z(zoomwavw) [winfo width .zoom.c]
	set z(zoomwavh) [winfo height .zoom.c]
	set z(f) [expr $z(f) * $factor]

	set start [Marker2Sample m1]
	set end   [Marker2Sample m2]

4488
4489
4490
4491
4492
4493
4494
4495
4496
















4497
4498
4499
4500
4501
4502
4503
4641
4642
4643
4644
4645
4646
4647


4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670







-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







	puts $out "set v(showspeg) \{$v(showspeg)\}"
	puts $out "set v(linkfile) \{$v(linkfile)\}"

	puts $out "set f(skip)  $f(skip)"
	puts $out "set f(ipath) $f(ipath)"
	puts $out "set f(ihttp) $f(ihttp)"

	puts $out "set s(fftlen) $s(fftlen)"
	puts $out "set s(anabw)  $s(anabw)"
	puts $out "set s(fftlen)  $s(fftlen)"
	puts $out "set s(anabw)   $s(anabw)"
	puts $out "set s(wintype) $s(wintype)"
	puts $out "set s(ref)     $s(ref)"
	puts $out "set s(range)   $s(range)"
	puts $out "set s(atype)   $s(atype)"
	puts $out "set s(lpcorder) $s(lpcorder)"
      
      if {[info exists snack::snackogg]} {
	puts $out "set ogg(nombr) $::ogg(nombr)"
	puts $out "set ogg(maxbr) $::ogg(maxbr)"
	puts $out "set ogg(minbr) $::ogg(minbr)"
	puts $out "set ogg(com)   $::ogg(com)"
	puts $out "set ogg(query) $::ogg(query)"
      }

	close $out
    }
}

proc SetCursor {flag} {
    foreach widget [winfo children .] {
	$widget config -cursor $flag

Changes to snack/doc/FileFormat.html.

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
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







+








-
+







-
+



+







*readProc;
<br>&nbsp; writeSamplesProc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*writeProc;
<br>&nbsp; seekProc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*seekProc;
<br>&nbsp; freeHeaderProc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*freeHeaderProc;
<br>&nbsp; configureProc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*configureProc;
<br>&nbsp; struct Snack_FileFormat *nextPtr;
<br>} Snack_FileFormat;
<p>char *<b>name</b>
<p>char *<b>guessFileTypeProc </b>(char *buf, int len)
<p>int&nbsp; <b>getHeaderProc</b> (Sound *s, Tcl_Interp *interp, Tcl_Channel
ch, Tcl_Obj *obj, char *buf)
<p>char *<b>extensionFileTypeProc</b> (char *buf);
<p>int&nbsp; <b>putHeaderProc</b> (Sound *s, Tcl_Interp *interp, Tcl_Channel
ch, Tcl_Obj *obj, int length)
ch, Tcl_Obj *obj, int objc, Tcl_Obj *CONST objv[], int length)
<p>int&nbsp; <b>openProc</b> (Sound *s, Tcl_Interp *interp,Tcl_Channel
*ch, char *mode)
<p>int&nbsp; <b>closeProc </b>(Sound *s, Tcl_Interp *interp, Tcl_Channel
*ch)
<p>int&nbsp; <b>readSamplesProc</b> (Sound *s, Tcl_Interp *interp, Tcl_Channel
ch, char *inBuffer, float *outBuffer, int length)
<p>int&nbsp; <b>writeSamplesProc</b> (Sound *s, Tcl_Channel ch, Tcl_Obj
*obj, char *buffer, int length)
*obj, int start, int length)
<p>int&nbsp; <b>seekProc</b> (Sound *s, Tcl_Interp *interp, Tcl_Channel
ch, int position)
<p>void <b>freeHeaderProc</b> (Sound *s)
<p>int&nbsp; <b>configureProc</b>(Sound *s, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
<br>&nbsp;
<h3>
DESCRIPTION</h3>
<b>Snack_CreateFileFormat</b> is used to define a new kind of sound file
format. A number of procedures can be specified in a Snack_FileFormat structure
to handle sound data I/O, header parsing, etc. The file SphereFile.c serves
as good example of how these routines are intended to be used.

Changes to snack/doc/SnackLib.html.

8
9
10
11
12
13
14
15
16


17
18
19
20
21
22
23
8
9
10
11
12
13
14


15
16
17
18
19
20
21
22
23







-
-
+
+







</head>
<body text="#000000" bgcolor="#FFFFFF" link="#0000EE" vlink="#551A8B" alink="#FE0000">

<center>
<h1>
<font face="Arial,Helvetica">Snack library functions</font></h1></center>
<tt>This is the public API of Snack to be used by C/C++-level extensions.
The functions are contained in Snack's stub library, libsnackstub2.0.a
(unix), snackstub20.lib (win). Linking with this will make your extension
The functions are contained in Snack's stub library, libsnackstub2.1.a
(unix), snackstub21.lib (win). Linking with this will make your extension
usable with different versions of Snack without recompilation.</tt><tt></tt>
<p><tt><a href="Callback.html">Snack_AddCallback</a></tt><tt></tt>
<p><tt><a href="AddSubCmd.html">Snack_AddSubCmd</a></tt><tt></tt>
<p><tt><a href="SampConv.html">Snack_Alaw2Lin</a></tt><tt></tt>
<p><tt><a href="CreateFilter.html">Snack_CreateFilterType</a></tt><tt></tt>
<p><tt><a href="FileFormat.html">Snack_CreateFileFormat</a></tt><tt></tt>
<p><tt><a href="SoundObj.html">Snack_DeleteSound</a></tt><tt></tt>

Changes to snack/doc/SphereFile.txt.

1
2
3
4
5
6


7

8

9



1
2
3
4
5
6
7
8

9
10
11

12
13
14






+
+
-
+

+
-
+
+
+
If you have configured Snack to use the NIST/Sphere file format you have
to explicitly add this file format in your script using the
'package require snacksphere' command after 'package require snack'. 
This will make Snack automatically recognize this file format in addition 
to those already built-in, such as WAV, AU, and AIFF. 

See ../demos/tcl/SphereTest.tcl for an example on how to use the package.

Writing the Sphere file format is not supported yet.
Writing files in the Sphere file format is not supported yet.

There seems to be a problem with reading some long compressed
See ../demos/SphereTest.tcl for an example.
NIST/Sphere files. One solution is to use the program sph_convert
to convert these files to wav-format before using them.
The program is available from http://morph.ldc.upenn.edu/Using/

Changes to snack/doc/python-man.html.

1
2
3
4
5
6

7
8
9
10
11

12
13
14
15
16
17
18
1
2
3
4
5

6
7
8
9
10

11
12
13
14
15
16
17
18





-
+




-
+







<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
   <meta name="GENERATOR" content="Mozilla/4.72 [en] (X11; U; Linux 2.2.14-5.0 i686) [Netscape]">
   <title>tkSnack manual v2.0</title>
   <title>tkSnack manual v2.1</title>
</head>
<body>

<h1>
Snack manual, version 2.0</h1>
Snack manual, version 2.1</h1>

<h2>
Installing Snack</h2>
First you need to install Snack according to its installation instruction.
In order to use Snack you need to put the file tkSnack.py somewhere in
your Python path.
<h2>
1089
1090
1091
1092
1093
1094
1095
1096



1097
1098
1089
1090
1091
1092
1093
1094
1095

1096
1097
1098
1099
1100







-
+
+
+


use:
<blockquote>
<pre>tkSnack.create_waveform(NonSnackCanvas, sound=tada)</pre>
</blockquote>

<p>
<hr>
<br>Last modified: September 17, 2000
<br>
<pre><font face="Arial, Helvetica"><font color="#FF6600"><font size=-1>Last updated&nbsp;</font></font></font><script LANGUAGE="JavaScript">document.write(document.lastModified)</script>
</pre>
</body>
</html>

Changes to snack/doc/tcl-man.html.

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
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







-
+






+
+
+


















+
+
+
+
+
+







<body text="#000000" bgcolor="#FFFFFF" link="#0000EE" vlink="#551A8B" alink="#FE0000">

<h1>

<hr></h1>

<h1>
<b>Snack v2.0.7 manual</b></h1>
<b>Snack v2.1.6 manual</b></h1>
<font color="#FF6600">Last updated&nbsp;</font><script LANGUAGE="JavaScript">document.write(document.lastModified)</script>

<dl>
<dt>
<a href="#audio">snack::audio</a></dt>

<dt>
<a href="#debug">snack::debug</a></dt>

<dt>
<a href="#filter">snack::filter</a></dt>

<dt>
<a href="#mixer">snack::mixer</a></dt>

<dt>
<a href="#sound">snack::sound</a></dt>

<dt>
<a href="#spectrogram">spectrogram canvas item</a></dt>

<dt>
<a href="#section">spectrum section canvas item</a></dt>

<dt>
<a href="#waveform">waveform canvas item</a></dt>

<dt>
&nbsp;</dt>

<dt>
<a href="#defpack">Standard extension packages</a> (sound, snackogg, snacksphere)</dt>

<dt>
&nbsp;</dt>

<dt>
<a href="SnackLib.html">Snack library</a></dt>
</dl>

95
96
97
98
99
100
101











102
103
104
105
106
107
108
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







+
+
+
+
+
+
+
+
+
+
+







Useful to prevent clipping when playing many simultaneous sounds. If no
value is specified the current factor is returned, default is 1.0.</blockquote>
<b>snack::audio selectInput</b><i> ?device?</i>
<blockquote>Selects an audio input device to be used as default.</blockquote>
<b>snack::audio stop</b>
<ul>Stops all playback on the audio device.</ul>

<hr>
<h3>
<a NAME="debug"></a>NAME</h3>
snack::debug - Control Snack debugging facilities
<h3>
SYNOPSIS</h3>
<b>snack::debug</b> level ?logFile? ?audioDumpFile?
<h3>
DESCRIPTION</h3>
The debug command is used to control the debugging facilities of Snack. The level flag is an integer (1-5) specifying the detail level of the generated debug log. Level 1 just prints entry/exit points of sound commands during execution. An optional second filename argument can be given to specify a file where the log will be written. An optional third filename can be given to specify a file where a raw dump of all audio being played through the audio device is to be generated. The sound file will be created in RAW (headerless) format. Note that debugging has to be turned on for each individual <a href="#sound">sound</a> object of interest. Reports on bugs/problems with Snack should typically include a minimal script that shows the problem, any associated sound files, and a debug log in order to facilitate a quick solution.
<p>
<hr>
<h3>
<a NAME="filter"></a>NAME</h3>
snack::filter - Create and manipulate filters
<h3>
SYNOPSIS</h3>
<b>snack::filter type</b> ?arg? ...
147
148
149
150
151
152
153


154
155
156
157
158
159
160
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182







+
+







<i>shape</i>
is a value between 0.0 and 1.0 used to influence the shape of the signal.
<i>type</i>
can be any of rectangle, triangle, sine, noise, or sampled. In the case
of sampled the generator will repeatedly get data from the sound it is
applied on. <i>ntot</i> specifies how many samples to generate. The default,
-1, will generate forever.</blockquote>
<b>iir</b><i> ?-denominator list? ?-dither value? ?-impulse list? ?-noise value? ?-numerator list?</i>
<blockquote>Creates an IIR or FIR filter. For FIR filters the coefficients are given as a list using the -impulse option. For IIR filters the coefficients are given as lists using the options -numerator and -denominator. The option -dither specifies the amount of triangular dithering to add to the output. The option -noise  specifies the amount of additive gaussian noise to add to the output.</blockquote>
<b>map</b><i> val ?val val val ...?</i>
<blockquote>Applies a linear transformation on each sample frame. For one
channel sounds this is simply a multiplication. For multi-channel sounds,
a transformation matrix can be specified with values row by row. One column
per channel is needed. If mono output is used, only one row needs to be
specified. If stereo output is used, only two rows needs to be specified.
If only one value is specified and the filter is used for multi-channel
212
213
214
215
216
217
218
219

220
221
222
223
224
225
226
234
235
236
237
238
239
240

241
242
243
244
245
246
247
248







-
+







<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; snack::sound ?name? ?options?
<br><a href="#DESCRIPTION">DESCRIPTION</a>
<br><a href="#CREATING SOUNDS">CREATING SOUNDS</a>
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="#sfile">snack::sound
?name? ?-load filename?&nbsp;<i> </i>?-file filename?&nbsp; ?-channel channelname?
?-rate f? ?-channels n? ?-encoding fmt? ?-fileformat fmt? ?-skiphead n?
?-byteorder endianess? ?-guessproperties boolean?&nbsp; ?-buffersize n?
?-precision prec? -changecommand procedure?</a>
?-precision prec? -changecommand procedure? ?-debug level?</a>
<br><a href="#SOUND COMMAND">SOUND COMMAND</a>
<dd>
<a href="#sapp"><i>soundName </i><b>append variable</b> <b>?-rate f? ?-channels
n? ?-encoding fmt? ?-skiphead n? ?-byteorder endianess? ?-start start?
?-end end? ?-guessproperties boolean?</b></a></dd>

<dd>
259
260
261
262
263
264
265
266

267
268
269
270
271
272
273
281
282
283
284
285
286
287

288
289
290
291
292
293
294
295







-
+








<dd>
<a href="#sdest"><i>soundName </i><b>destroy</b></a></dd>

<dd>
<a href="#sfft"><i>soundName </i><b>dBPowerSpectrum ?-start sample? ?-end
sample? ?-skip samples? ?-fftlength length? ?-windowlength length? ?-channel
channel? ?-preemphasis factor?</b></a></dd>
channel? ?-preemphasisfactor factor? ?-windowtype type? ?-analysistype type? ?-lpcorder n?</b></a></dd>

<dd>
<a href="#sfilter"><i>soundName </i><b>filter filterName ?-start sample?
?-end sample? ?-continedrain boolean? ?-progress procedure?</b></a></dd>

<dd>
<a href="#sflush"><i>soundName </i><b>flush</b></a></dd>
295
296
297
298
299
300
301
302
303





304
305
306
307
308
309
310
317
318
319
320
321
322
323


324
325
326
327
328
329
330
331
332
333
334
335







-
-
+
+
+
+
+








<dd>
<a href="#spitch"><i>soundName </i><b>pitch ?-start start? ?-end</b> <b>end?
?-maxpitch val? ?-minpitch val? ?-progress callback?</b></a></dd>

<dd>
<a href="#splay"><i>soundName </i><b>play ?-start start? ?-end end? ?-output
jack? ?-blocking boolean? -command ?callback? ?-device outputDevice? ?-rate
rate? ?-channels channels?</b></a></dd>
jack? ?-blocking boolean? -command ?callback? ?-device outputDevice? ?-devicerate rate? ?-devicechannels channels?</b></a></dd>

<dd>
<a href="#spower"><i>soundName </i><b>power ?-start sample? ?-end
sample? ?-framelength length? ?-windowlength length? ?-windowtype type? ?-preemphasisfactor factor? ?-channel channel? ?-progress callback?</b></a></dd>

<dd>
<a href="#sread"><i>soundName </i><b>read </b><i>filename</i><b> ?-rate
f? ?-channels n? ?-encoding fmt? ?-skiphead n? ?-byteorder endianess??-start
start? ?-end end? ?-guessproperties boolea</b></a><b><a href="#srec">n?
?-progress procedure?</a></b></dd>

344
345
346
347
348
349
350
351

352
353
354
355
356
357
358
359
360
361
362
363

364
365

366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383

384
385
386
387
388
389
390
369
370
371
372
373
374
375

376

377
378
379
380
381
382
383
384
385
386

387
388

389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406

407
408
409
410
411
412
413
414







-
+
-










-
+

-
+

















-
+







<h3>
<a NAME="CREATING SOUNDS"></a>CREATING SOUNDS</h3>
The sound command is used to create sound objects. It can take several
different forms, depending on the option argument. The legal forms are:
<p><a NAME="sfile"></a><b>snack::sound </b><i>?soundName? ?-load filename?</i>&nbsp;<i>
?-file filename?</i>&nbsp;<i> ?-channel channelname? ?-rate f? ?-channels
n? ?-encoding fmt? ?-fileformat fmt? ?-skiphead n? ?-byteorder endianess?
?-guessproperties boolean?&nbsp; ?-buffersize n? ?-precision prec? ?-changecommand
?-guessproperties boolean?&nbsp; ?-buffersize n? ?-precision prec? ?-changecommand procedure? ?-debug level?</i>
procedure?</i>
<p><i>soundName</i> specifies the name of the sound. If it is omitted then
Snack picks a name of the form sound<i>n</i>, where <i>n</i> is an integer.
The <b>-load</b> option specifies that the file <i>filename</i> should
be read into memory after creating the sound. The <b>-file</b> option specifies
an on-disk file which should be linked to the sound. The <b>-channel</b>
option specifies that audio data resides on a channel which should be linked
to the sound. In these cases the audio data is not loaded into memory,
which is useful when playing large files or when using streaming audio.
A value of 1 or larger must be specified for the <b>-channels</b> option
(<b>Mono</b>, or <b>Stereo</b> are also valid). If not specified a default value of 1 is assumed.
Possible values for sample encoding format
Possible values for sample encoding format, given using the <b>-encoding</b> option,
are <b>Lin16</b>, <b>Lin8offset</b>, <b>Lin8</b>,<b> Lin24</b>,
<b>Lin32</b>, <b>Float</b>, <b>Alaw</b>, or <b>Mulaw</b>, and if not given the default encoding is <b>Lin16</b>. The option <b>-rate</b> can take any positive value but usually only sample rates supported by the audio hardware are useful. Note that the default value is 16000, a common value for speech related applications, but less frequent for other uses, such as music.
<b>Lin32</b>, <b>Float</b>, <b>Alaw</b>, or <b>Mulaw</b>. Default encoding is <b>Lin16</b>. The option <b>-rate</b> can take any positive value but usually only sample rates supported by the audio hardware are useful. Note that the default value is 16000, a common value for speech related applications, but less frequent for other uses, such as music.
<b>-fileformat</b> works as for the <b>read</b> command.
<b>-skiphead</b> is used to skip an unknown file header of size <b>n</b> bytes.
Byte order can be specified as littleEndian or bigEndian using the
<b>-byteorder</b> option. The option
<b>-guessproperties</b>
is used to specify that Snack should try to infer properties, such as byte
order, sample encoding format, and sample rate for a raw file by analyzing
the contents of the file. Byte order is almost always detected correctly.
For channel based sounds the
<b>-buffersize</b> option can be used to specify
the size of the internal buffer in samples. The option <b>-precision</b>
is used to specify if sound data is to be handled using simple or double
precision internally. -<b>changecommand</b> is used to specify a procedure
which is to be called every time a property of the sound is changed. This
is the Tcl level counterpart of Snack_AddCallback(). The procedure should
expect one argument, one of the strings <i>New, More, </i>or<i> Destroy</i>.
This feature is particularly useful when embedding sound objects in other
higher level constructs.
higher level constructs. The flag -<b>debug</b> is used to control debug output for operations on the sound object. The option takes a level argument, an integer in the range 1-5, specifying the detail of the trace information.
<p><a NAME="SOUND COMMAND"></a>SOUND COMMAND
<br>When a sound object is created, Snack also creates a new object command
whose name is the same as the sound. This command is used to invoke various
operations (or sub-commands) on the sound. This is the current set:
<p><a NAME="sapp"></a><i>soundName</i> <b>append</b> <i>variable</i> <b>?-rate
f? ?-channels n? ?-encoding fmt? ?-skiphead n? ?-byteorder endianess? ?-start
start? ?-end</b> <b>end? ?-fileformat fmt?</b> <b>?-guessproperties boolean?</b>
411
412
413
414
415
416
417
418

419
420
421
422
423
424
425
435
436
437
438
439
440
441

442
443
444
445
446
447
448
449







-
+







<ul>Concatenates the sample data from <b>sound</b> to the end of <i>soundName</i>.
The sound to be added must be of the same type as the base sound, i.e. have the same sample rate, sample
encoding format, and number of channels). Note that even an initially empty sound has these properties defined. This command applies to in-memory
sounds only.</ul>
<a NAME="sconf"></a><i>soundName </i><b>configure option value ...</b>
<ul>The configure command is used to set options for a sound. Options can
be any of the following: <b>-load, -file, -channel, -rate, -channels, -encoding,
-skiphead, -byteorder, -guessproperties</b>, <b>-precision,</b> and <b>-buffersize</b>.
-skiphead, -byteorder, -guessproperties, -precision, -debug</b> and <b>-buffersize</b>.
See the <a href="#sfile">sound</a> command for more information on these.</ul>
<a NAME="sconv"></a><i>soundName </i><b>convert option value ...</b>
<ul>The convert command is used to convert a sound to a different sample
encoding, sample rate, or number of channels. Options can be any of the
following: <b>-rate, -channels,</b> <b>-encoding, </b>and <b>-progress</b>.
A value of 1 or larger must be specified for the <b>-channels</b> option
(<b>Mono</b>, or <b>Stereo</b> are also valid). Only conversions from many
463
464
465
466
467
468
469
470
471
472



473
474

475
476
477
478
479
480
481

482
483
484
485
486
487
488
487
488
489
490
491
492
493



494
495
496
497

498


499
500
501
502

503
504
505
506
507
508
509
510







-
-
-
+
+
+

-
+
-
-




-
+







bigEndian or littleEndian.
<p><i>soundName </i><b>data ?-start start? ?-end end?</b> <b>?-fileformat
fileformat? -byteorder ?endianess?</b>
<p>This command applies to in-memory sounds only.</ul>
<a NAME="sdest"></a><i>soundName </i><b>destroy</b>
<ul>Removes the sound command and frees the storage associated with it.</ul>
<a NAME="sfft"></a><i>soundName </i><b>dBPowerSpectrum</b> <b>?-start sample?
?-end sample? ?-fftlength length? ?-windowlength length? ?</b>-<b>windowtype
type?</b><i> </i><b>?-skip samples? ?-channel channel? ?-preemphasisfactor
factor?</b>
?-end sample? ?-fftlength length? ?-windowlength length? ?-windowtype
type? ?-skip samples? ?-channel channel? ?-preemphasisfactor
factor? ?-analysistype type? ?-lpcorder n?</b>
<ul>Computes the log FFT power spectrum of the sound at <b>-start</b> and
returns a list of dB values. See the
returns a list of dB values. Optionally an end point can be given, using
<a href="#section">section item</a>
for the rest of the options. Optionally an ending point can be given, using
<b>-end</b>.
In this case the result is the average of consecutive FFT's in the specified
range. Their default spacing is taken from <b>-fftlength</b> but this can
be changed using the <b>-skip</b> option which specifies how many points
to move the FFT window forward at each step.</ul>
to move the FFT window forward at each step. See the <a href="#section">section item</a> for the rest of the options. </ul>
<a NAME="sfilter"></a><i>soundName </i><b>filter filterName ?-start sample?
?-end sample? ?-continuedrain boolean? ?-progress procedure?</b>
<ul>Applies the <a href="#filter">filter</a> <b>filterName</b> to the sound.
Optionally, a range to apply the filter on can be specified. The <b>-continuedrain
</b>option
specifies whether the filter should be allowed to drain out past the end
point. See the <a href="#sread">read</a> command for a description on how
519
520
521
522
523
524
525
526

527
528
529
530
531
532


533
534
535
536
537
538
539
540
541
542
543
544
545
546

547
548
549
550
551
552
553


554





555
556
557
558
559
560
561
541
542
543
544
545
546
547

548
549
550
551
552


553
554
555
556
557
558
559
560
561
562
563
564
565
566
567

568
569
570
571
572
573


574
575
576
577
578
579
580
581
582
583
584
585
586
587
588







-
+




-
-
+
+













-
+





-
-
+
+

+
+
+
+
+







all of them are paused using <b>pause</b>.</ul>
<a NAME="spitch"></a><i>soundName </i><b>pitch ?-start start? ?-endend?
?-maxpitch val? ?-minpitch val? ?-progress procedure?</b>
<ul>Returns a list of pitch values computed using the AMDF method. The
values are spaced at 10ms intervals. A range of samples can be given using
<b>-start</b>
and <b>-end</b>. If a frequency range of valid pitch values is known this
can be specified using the options <b>-maxpitch</b> and <b>-minpitch</b>.
can be specified using the options <b>-maxpitch</b> (default 400) and <b>-minpitch</b> (default 60).
See the <a href="#sread">read</a> command for a description on how to use
the <b>-progress</b> option.</ul>
<a NAME="splay"></a><i>soundName </i><b>play ?-start start? ?-end end?
?-output jack??-blocking boolean? ?-command callback? ?-device outputDevice?
?-filter filter? ?-rate f? ?-channels n?</b>
<ul>Plays a sound. A range of samples to play can be specified using the
?-filter filter? ?-devicerate f? ?-devicechannels n?</b>
<ul>Plays a sound. A range of samples to be played can be specified using the
<b>-start</b>
and <b>-end</b> options. The <b>-output</b> option is used to specify any
of the possible output ports returned by the <a href="#outputs">audio outputs</a>
command. The <b>-blocking</b> option is used to specify whether playback
should be asynchronous or not, i.e. if it is to be played in the background
or if the <b>play</b> command should return only after the sound has been
played. Asynchronous playback from tclsh is only possible if the event
loop is running, using for example <b>vwait</b>. The <b>-command</b> option
specifies a command to be executed when the end of the sound is reached.
The <b>-device</b> option selects which audio output device to use. The
<b>-filter</b>
option is used to specify a <a href="#filter">filter</a> which is to be
applied during output. The audio device can be opened with different properties
from those of the sound object using <b>-rate</b> and <b>-channels</b>,
from those of the sound object using <b>-devicerate</b> and <b>-devicechannels</b>,
which might be useful in some rare cases. The option
<b>-starttime</b>
is used to schedule the start of playback (in ms) relative to a previous
play operation. All options are ignored if <b>play</b> is used to resume
a paused play operation. If a <b>play </b>command is issued while another
one is in progress, the latter one is queued up and starts to play as soon
as possible. The lag before this new sound is audible can be controlled
one is in progress, the new sound will start to play as soon
as possible given the internal buffering. The lag before the sound is audible can be controlled
using the <a href="#latency">snack::audio latency</a> command.</ul>
<a NAME="spower"></a><i>soundName </i><b>power ?-start sample? ?-end
sample? ?-framelength length? ?-windowlength length? ?-windowtype type? ?-preemphasisfactor factor? ?-channel channel? ?-progress callback?</b>
<ul>Returns a list of windowed log power values. The <b>-framelength</b> option specifies the intervals between the values. The option <b>-windowtype</b> is used to select windowing function, (valid values are Hamming, Hanning, Bartlett, Blackman, or Rectangle). <b>-windowlength</b> specifies the size
of the window in points. -<b>preemphasisfactor</b> is used to specify the amount of preemphasis applied to the signal prior to windowing. A range of samples can be given using
<b>-start</b> and <b>-end</b>. See the <a href="#sread">read</a> command for a description on how to use the <b>-progress</b> option and the <a href="#section">section item</a> for the <b>-channel</b> option.</ul>
<a NAME="sread"></a><i>soundName </i><b>read </b><i>filename</i><b> ?-fileformat
fmt?</b> <b>?-rate f? ?-channels n? ?-encoding fmt? ?-skiphead n? ?-byteorder
endianess? ?-start start? ?-end end?</b> <b>?-guessproperties boolean?
?-progress procedure?</b>
<ul>Reads new sound data from a file. Current supported file formats are
WAV, MP3, AU, SND, AIFF, SD, SMP, CSL, and RAW binary. The command returns
the file format detected. It is possible to force a file to be read as
649
650
651
652
653
654
655
656

657
658
659

660
661
662

663
664
665

666
667
668

669
670



671

672
673
674
675
676
677

678
679
680

681
682
683

684
685
686
687
688
689
690
691
692
693
694
695
696
697
698

699
700
701
702
703
704

705
706
707
708
709
710
711
712
713
714
715
716
717
718


719
720
721
722


723
724
725
726


727
728
729
730
731
732


733
734
735
736
737



738
739

740
741

742
743
744

745
746
747

748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765

766
767



768

769
770



771

772
773
774
775
776
777

778
779
780

781
782
783
784
785



786

787
788
789

790
791
792
793
794
795
796
797
798
799
800
801

802
803
804

805
806
807
808
809
810

811
812
813
814
815
816
817
818
819
820
821
822
823
824
825



826
827
828


829
830
831
832
833
834


835
836
837

838
839
840
841
842
843
844

845
846
847
848
849
850
851
852
853
854
855
856
857
858
859

860
861
862




863
864
865
866
867
868
869
870
871

872
873
874
875
876
877

878
879
880
881
882
883
884
885
886

887
888
889
890
891
892
893
894
895
896
897
898

899
900
901
902
903
904
905
906
907
908
909
910
911
912


913
914
915
916
917
918
919
920
921
922
923
924

925
926
927
928
929
930

931
932

933
934
935
936
937
938
939

940
941
942
943
944
945
946









947
948
949
950
951
676
677
678
679
680
681
682

683
684
685

686
687
688

689
690
691

692
693
694

695
696
697
698
699
700

701
702
703
704
705
706

707
708
709

710
711
712

713
714
715
716
717
718
719
720
721
722
723
724
725
726
727

728
729
730
731
732
733

734
735
736
737
738
739
740
741
742
743
744
745
746


747
748
749
750


751
752

753


754
755
756
757
758
759
760

761
762
763
764



765
766
767
768

769
770

771
772
773

774
775
776

777

778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793

794
795
796
797
798
799

800
801
802
803
804
805

806
807
808
809
810
811

812
813
814

815
816
817
818
819
820
821
822
823

824
825
826

827
828
829
830
831
832
833
834
835
836
837
838

839
840
841

842
843
844
845
846
847

848
849
850
851
852
853
854
855
856
857
858
859
860



861
862
863
864


865
866



867


868
869
870
871

872
873
874
875
876
877
878

879
880
881
882
883
884
885
886
887
888
889
890
891
892
893

894
895
896

897
898
899
900
901
902
903
904
905
906
907
908

909
910
911
912
913
914

915
916
917
918
919
920
921
922
923

924
925
926
927
928
929
930
931
932
933
934
935

936
937
938
939
940
941
942
943
944
945
946
947
948


949
950
951
952
953
954
955
956
957
958
959
960
961

962

963
964
965
966

967


968
969
970
971
972
973
974

975
976
977
978




979
980
981
982
983
984
985
986
987
988
989
990
991
992







-
+


-
+


-
+


-
+


-
+


+
+
+
-
+





-
+


-
+


-
+














-
+





-
+












-
-
+
+


-
-
+
+
-

-
-
+
+





-
+
+


-
-
-
+
+
+

-
+

-
+


-
+


-
+
-
















-
+


+
+
+
-
+


+
+
+
-
+





-
+


-
+





+
+
+
-
+


-
+











-
+


-
+





-
+












-
-
-
+
+
+

-
-
+
+
-
-
-

-
-
+
+


-
+






-
+














-
+


-
+
+
+
+








-
+





-
+








-
+











-
+












-
-
+
+











-
+
-




-
+
-
-
+






-
+



-
-
-
-
+
+
+
+
+
+
+
+
+





SYNOPSIS</h3>
<i>pathName</i> <b>create</b> <b>spectrogram</b> x y ?options value option
value ...?
<h3>
OPTIONS</h3>

<dd>
<i>-</i><b>anchor</b><i> anchorPos</i></dd>
-<b>anchor</b><i> anchorPos</i></dd>

<dd>
<i>-</i><b>brightness</b><i> value</i></dd>
-<b>brightness</b><i> value</i></dd>

<dd>
<i>-</i><b>channel</b><i> channel</i></dd>
-<b>channel</b><i> channel</i></dd>

<dd>
<i>-</i><b>colormap</b><i> colorlist</i></dd>
-<b>colormap</b><i> colorlist</i></dd>

<dd>
<i>-</i><b>contrast</b><i> value</i></dd>
-<b>contrast</b><i> value</i></dd>

<dd>
-<b>debug</b><i> level</i></dd>

<dd>
<i>-</i><b>end</b><i> sample</i></dd>
-<b>end</b><i> sample</i></dd>

<dd>
-<b>fftlength</b><i> length</i></dd>

<dd>
<i>-</i><b>gridcolor</b><i> color</i></dd>
-<b>gridcolor</b><i> color</i></dd>

<dd>
<i>-</i><b>gridfspacing</b><i> value</i></dd>
-<b>gridfspacing</b><i> value</i></dd>

<dd>
<i>-</i><b>gridtspacing</b><i> value</i></dd>
-<b>gridtspacing</b><i> value</i></dd>

<dd>
-<b>height</b><i> size</i></dd>

<dd>
-<b>pixelspersecond</b><i> value</i></dd>

<dd>
-<b>preemphasisfactor</b><i> factor</i></dd>

<dd>
-<b>sound</b><i> name</i></dd>

<dd>
<i>-</i><b>start</b><i> sample</i></dd>
-<b>start</b><i> sample</i></dd>

<dd>
-<b>tags </b><i>tagList</i></dd>

<dd>
<i>-</i><b>topfrequency</b><i> frequency</i></dd>
-<b>topfrequency</b><i> frequency</i></dd>

<dd>
-<b>width</b><i> size</i></dd>

<dd>
-<b>windowtype</b><i> type</i></dd>

<dd>
-<b>winlength</b><i> length</i></dd>

<h3>
DESCRIPTION</h3>
This command draws a spectrogram of a sound on a canvas. The options <i>-</i><b>anchor</b>,
and -<b>tags</b> work as for ordinary Tk canvas items. -<b>sound</b> specifies
This command draws the spectrogram of a sound. The options -<b>anchor</b>,
and -<b>tags</b> work as for other Tk canvas items. -<b>sound</b> specifies
which sound object to link to and -<b>height</b> the height of the spectrogram.
The option <b>-fftlength</b> specifies the number of FFT points (8, 16,
32, 64, 128, 256, 512, 1024, 2048, or 4096). The option <b>-windowtype</b>
is used to select windowing function, (valid values are Hamming, Hanning,
32, 64, 128, 256, 512, 1024, 2048, or 4096). The default value is 256. 
The option <b>-windowtype</b> is used to select windowing function, (valid values are Hamming, Hanning, Bartlett, Blackman, or Rectangle). The default window type is Hamming. <b>-winlength</b> specifies the size
Bartlett, Blackman, or Rectangle). <b>-winlength</b> specifies the size
of the hamming window, which should be equal to or less than the number
of FFT points. -<b>preemphasisfactor</b> is used to specify the amount
of preemphasis applied to the signal prior to the FFT calculation. <b>-start</b>
of FFT points. The default window length is 128. -<b>preemphasisfactor</b> is used to specify the amount
of preemphasis applied to the signal prior to the FFT calculation, default 0.97. <b>-start</b>
and <b>-end</b> controls which part of the sound to display. <b>-pixelspersecond</b>
determines the scaling factor in the x-direction. The <b>-width</b> option
specifies the width of the spectrogram. If both <b>-width</b> and <b>-pixelspersecond</b>
are specified the spectrogram will be cut at one end depending on if a
<b>-start</b>
or <b>-end</b> option was also given. Use the <b>-channel</b> option to
or <b>-end</b> option was also given. Currently, spectrograms
have a width limit of 32767 pixels. Use the <b>-channel</b> option to
select which channel to show for multichannel sounds. Use left, right,
both, all, -1 (all) or a channel number counting from 0 (left). The default
is to show all, i.e. to add all channels. <i>-</i><b>brightness</b> and
<i>-</i><b>contrast</b>
takes values beteween -100.0 and 100.0 with the default being 0.0. <i>-</i><b>topfrequency</b>
is to show all, i.e. to add all channels. -<b>brightness</b> and
-<b>contrast</b>
takes values beteween -100.0 and 100.0 with the default being 0.0. -<b>topfrequency</b>
is the frequency value at the top of the spectrogram, default is the Nyquist
frequency. <i>-</i><b>gridtspacing</b> is the spacing between markers in
frequency. -<b>gridtspacing</b> is the spacing between markers in
seconds (default 0 means no grid) and
<i>-</i><b>gridfspacing</b> is the
-<b>gridfspacing</b> is the
frequency spacing in Hz (default 0 means no grid). -<b>gridcolor</b> specifies
the color of the grid. A colormap for the spectrogram is given with the
<i>-</i><b>colormap</b>
-<b>colormap</b>
option. It takes a list of colors as parameter and at least two must be
specified. The first color is used for the lowest intensity in the spectrogram.
An empty list gives the default 32-level grey scale. Currently, spectrograms
An empty list gives the default 32-level grey scale. The flag -<b>debug</b> is used to control debug output for the item. The option takes a level argument, an integer in the range 1-5, specifying the detail of the trace information.
have a width limit of 32767 pixels.
<br>See also the code examples in the widget demonstration.
<h3>

<hr></h3>

<h3>
<a NAME="section"></a>NAME</h3>
section - Spectrum section canvas item
<h3>
SYNOPSIS</h3>
<i>pathName</i> <b>create</b> <b>section</b> x y ?options value option
value ...?
<h3>
OPTIONS</h3>

<dd>
<i>-</i><b>anchor</b><i> anchorPos</i></dd>
-<b>anchor</b><i> anchorPos</i></dd>

<dd>
-<b>analysistype</b><i> type</i></dd>

<dd>
<i>-</i><b>channel</b><i> channel</i></dd>
-<b>channel</b><i> channel</i></dd>

<dd>
-<b>debug</b><i> level</i></dd>

<dd>
<i>-</i><b>end</b><i> sample</i></dd>
-<b>end</b><i> sample</i></dd>

<dd>
-<b>fftlength</b><i> length</i></dd>

<dd>
<i>-</i><b>fill</b><i> color</i></dd>
-<b>fill</b><i> color</i></dd>

<dd>
<i>-</i><b>frame</b><i> boolean</i></dd>
-<b>frame</b><i> boolean</i></dd>

<dd>
-<b>height</b><i> size</i></dd>

<dd>
-<b>lpcorder</b><i> n</i></dd>

<dd>
<i>-</i><b>maxvalue</b><i> value</i></dd>
-<b>maxvalue</b><i> value</i></dd>

<dd>
<i>-</i><b>minvalue</b><i> value</i></dd>
-<b>minvalue</b><i> value</i></dd>

<dd>
-<b>preemphasisfactor</b><i> factor</i></dd>

<dd>
<b>-skip</b><i> points</i></dd>

<dd>
-<b>sound</b><i> name</i></dd>

<dd>
<i>-</i><b>start</b><i> sample</i></dd>
-<b>start</b><i> sample</i></dd>

<dd>
<i>-</i><b>stipple</b><i> value</i></dd>
-<b>stipple</b><i> value</i></dd>

<dd>
-<b>tags </b><i>tagList</i></dd>

<dd>
<i>-</i><b>topfrequency</b><i> frequency</i></dd>
-<b>topfrequency</b><i> frequency</i></dd>

<dd>
-<b>width</b><i> size</i></dd>

<dd>
-<b>windowtype</b><i> type</i></dd>

<dd>
-<b>winlength</b><i> length</i></dd>

<h3>
DESCRIPTION</h3>
This command draws an FFT log power spectrum section of a sound on a canvas.
The options <i>-</i><b>anchor</b>, -<b>fill</b>, -<b>stipple</b>, and -<b>tags</b>
work as for ordinary Tk canvas line items. -<b>sound</b> specifies which
This command draws the FFT log power spectrum section of a sound.
The options -<b>anchor</b>, -<b>fill</b>, -<b>stipple</b>, and -<b>tags</b>
work as for other Tk canvas line items. -<b>sound</b> specifies which
sound object to link to and -<b>height</b> and -<b>width</b> the height/width
of the section.The option <b>-fftlength</b> specifies the number of FFT
points (8, 16, 32, 64, 128, 256, 512, 1024, 2048, or 4096). The option
of the section. The option <b>-fftlength</b> specifies the number of FFT
points (8, 16, 32, 64, 128, 256, 512, 1024, 2048, or 4096). The default value is 512. The option <b>-windowtype</b> is used to select windowing function, (valid values are Hamming, Hanning, Bartlett, Blackman, or Rectangle). The default window type is Hamming. <b>-analysistype</b> is either <b>FFT</b> (default) or <b>LPC</b>, for LPC analysis the order is specified using <b>-lpcorder</b> (default 20). <b>-winlength</b> specifies the size
<b>-windowtype</b>
is used to select windowing function, (valid values are Hamming, Hanning,
Bartlett, Blackman, or Rectangle). <b>-winlength</b> specifies the size
of the window, which should be equal to or less than the number of FFT
points. -<b>preemphasisfactor</b> is used to specify the amount of preemphasis
applied to the signal prior to the FFT calculation.
points. The default window length is 128. -<b>preemphasisfactor</b> is used to specify the amount of preemphasis
applied to the signal prior to the FFT calculation (default 0.0).
<b>-start</b> and <b>-end</b>
controls which part of the sound to display.
<i>-</i><b>topfrequency</b>
-<b>topfrequency</b>
is the frequency value at the right end of the section. -<b>maxvalue</b>
and -<b>minvalue</b> specify the range (in dB) which will be shown (default
0.0 to -80.0). Use the <b>-channel</b> option to select which channel to
show for multichannel sounds. Use left, right, both, all, -1 (all) or a
channel number counting from 0 (left). The default is to show all, i.e.
to add all channels. <b>-frame</b> specifies whether a frame will be drawn
around the spectrum section.
around the spectrum section. The flag -<b>debug</b> is used to control debug output for the item. The option takes a level argument, an integer in the range 1-5, specifying the detail of the trace information.
<br>See also the code examples in the widget demonstration.
<p>
<hr>
<h3>
<a NAME="waveform"></a>NAME</h3>
waveform - Waveform canvas item
<h3>
SYNOPSIS</h3>
<i>pathName</i> <b>create</b> <b>waveform </b>x y ?option value option
value ...?
<h3>
OPTIONS</h3>

<dd>
<i>-</i><b>anchor</b><i> anchorPos</i></dd>
-<b>anchor</b><i> anchorPos</i></dd>

<dd>
<i>-</i><b>channel</b><i> channel</i></dd>
-<b>channel</b><i> channel</i></dd>

<dd>
-<b>debug</b><i> level</i></dd>

<dd>
-<b>end </b><i>sample</i></dd>

<dd>
-<b>fill </b><i>color</i></dd>

<dd>
<i>-</i><b>frame</b><i> boolean</i></dd>
-<b>frame</b><i> boolean</i></dd>

<dd>
-<b>height</b><i> size</i></dd>

<dd>
<i>-</i><b>limit</b><i> value</i></dd>
-<b>limit</b><i> value</i></dd>

<dd>
-<b>pixelspersecond</b><i> value</i></dd>

<dd>
<b>-progress</b> <i>procedure</i></dd>

<dd>
<i>-</i><b>shapefile</b><i> filename</i></dd>
-<b>shapefile</b><i> filename</i></dd>

<dd>
-<b>sound</b><i> name</i></dd>

<dd>
-<b>start </b><i>sample</i></dd>

<dd>
-<b>stipple </b><i>bitmap</i></dd>

<dd>
<i>-</i><b>subsample</b><i> value</i></dd>
-<b>subsample</b><i> value</i></dd>

<dd>
-<b>tags </b><i>tagList</i></dd>

<dd>
-<b>width</b><i> size</i></dd>

<dd>
-<b>zerolevel</b><i> boolean</i></dd>

<h3>
DESCRIPTION</h3>
This command draws the waveform of a sound on a canvas. The options <i>-</i><b>anchor</b>,
-<b>fill</b>, -<b>stipple</b>, and -<b>tags</b> work as for ordinary Tk
This command draws the waveform of a sound. The options -<b>anchor</b>,
-<b>fill</b>, -<b>stipple</b>, and -<b>tags</b> work as for other Tk
canvas line items. -<b>sound</b> specifies which sound object to link to
and -<b>height</b> the height of the waveform. The options <b>-start</b>
and <b>-end</b> controls which part of the sound to display. -<b>pixelspersecond</b>
determines the scaling factor in the x-direction. The <b>-width</b> option
specifies the width of the waveform. If both <b>-width</b> and <b>-pixelspersecond</b>
are specified the waveform will be cut at one end depending on if a <b>-start</b>
or <b>-end</b> option was also given. Use the <b>-channel</b> option to
select which channel to show for multichannel sounds. Use left, right,
both, all, -1 (all) or a channel number counting from 0. The default is
to show all, i.e. to add all channels. Use <b>-limit</b> to specify the
maximum shown value for the sound amplitude. <b>-zerolevel</b> specifies
whether the zero level will be displayed and <b>-frame</b> whether a frame
whether the zero level will be displayed (default yes) and <b>-frame</b> whether a frame will be drawn around the waveform (default no). The -<b>subsample</b> option
will be drawn around the waveform. The <i>-</i><b>subsample</b> option
is useful for large sounds to specify how precisely they should be analyzed
for shape calculation. The default value 1 uses every sample in the sound
to draw the waveform envelope, which can be slow for large sounds. A value
of 10 uses every 10th. Care should be used when specifying this because
a large value could lead to an incorrect envelope shape. The option -<b>shapefile</b>
a large value could lead to an incorrect envelope shape. The option -<b>shapefile</b> is used to specify a file for storing/retrieving precomputed waveform shape
is used to specify a file for storing/retrieving precomputed waveform shape
information. If the file doesn't exist it is created. If it exists it is
information. The file specified is created if it does not already exist. If it exists it is
accessed instead of the sound data itself, thus speeding up on-screen display.
There exists two convenience routines, snack::deleteInvalidShapeFile and
snack::makeShapeFileDeleteable, which can be used to enclose a <b>create
waveform</b> statement when using the shape file functionality. These will
make sure that shape files are handled properly, see the demo cool.tcl,
for an example of this. See the <a href="#sread">read</a> command for a
description on how to use the <b>-progress</b> option.
description on how to use the <b>-progress</b> option. The flag <b>-debug</b> is used to control debug output for the item. The option takes a level argument, an integer in the range 1-5, specifying the detail of the trace information.
<br>See also code examples in the widget demonstration.
<p>
<hr>
<p>The command <b>package require snack</b> gives you access to all commands
described above.
<br>There is also a package called <b>sound</b> which gives you the <b>snack::audio,
snack::filter, snack::mixer, </b>and <b>snack::sound </b>commands. This is useful on some systems if you want to use the tclsh interpreter.
<a NAME="defpack"></a>
<h3>Standard extension packages</h3>
<p>The following packages are included in the Snack distribution or can be downloaded separately.
<p><b>sound</b>
<ul>The <b>sound</b> package gives you the <b>snack::audio, snack::filter, snack::mixer, </b>and <b>snack::sound </b>commands. Basicly the same functions as the <b>snack</b> package except for graphics. This is useful on some systems if you want to use the tclsh interpreter.</ul>
<p><b>snackogg</b>
<ul>The <b>snackogg</b> package adds support for the Ogg/Vorbis compressed sound file format. Ogg format files and streams are detected automatically. Encoding is supported. Simply use the extension .ogg when writing files or use the option <b>-fileformat ogg</b>. When creating Ogg files the additional options <b>-nominalbitrate</b>, <b>-maxbitrate</b>, <b>-minbitrate</b>, and <b>-comment</b> apply.</ul>
<p><b>snacksphere</b>
<ul>The <b>snacksphere</b> package adds support for reading the NIST/Sphere sound file formats. Sphere files are detected automatically.</ul>
<p>
<hr WIDTH="100%">
<br><a href="http://www.speech.kth.se/snack/index.html">Snack home</a>
</body>
</html>

Changes to snack/ext/README.

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
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

-
+











-
+









+







How to write extensions to Snack
-----------------------------------
--------------------------------

You can create custom commands that operate on Snack's sound objects. These new
commands should be written in C/C++ and can be used just as any other Snack
sound command. To invoke 'newcommand' on the sound 'snd' you would type:

snd newcommand

Use Snack_AddSubCmd() as shown in the example square.c to associate a new
command name and a custom C/C++ function.

The preferred way of creating a Snack extension is to link with
Snack's stub library (unix: libsnackstub2.0.a, win: snackstub20.lib).
Snack's stub library (unix: libsnackstub2.1.a, win: snackstub21.lib).
In this way your extension should be usable with different versions of Snack
without recompilation.
More general information on stub libraries at http://dev.scriptics.com/doc/tea/

It is also possible to use the old method and link with libsnack.so (HP: .sl).
On Unix you might also have to set the variable LD_LIBRARY_PATH
(HP: SHLIB_PATH) to the directory containing the library file. The drawback
with this method is that you'll have to recompile your extension with each
new release of Snack and Tcl.



Building the sample extension on Unix
-------------------------------------

change directory to the example extension directory (where this README file
is located)
45
46
47
48
49
50
51
52
53



54
55
56
























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







-
-
+
+
+



+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
setenv LD_LIBRARY_PATH `pwd`

Run the Snack extension using

./test.tcl


Windows
-------

Building the sample extension on Windows
----------------------------------------

The Snack MSVC workspace (win/snack.dsw) contains a project for the example
square extension.  Try the extension using the test.tcl script in ext/.



Package loading
----------------------------------------

The demonstration script uses the 'load' command to load the extension.
Is is also possible to load it in the same manner as the Snack package,
using a 'package require' command.
Create a pkgIndex.tcl-file in the same directory as the binary with the
following statement

package ifneeded square 1.0 [list load [file join $dir libsquare[info sharedlibextension]]]

It is now possible to install your extension as a Tcl package in the same
way as Snack. Put the library file and the index file in a sibling 
directory to the Snack directory. Use the command 'package require square'.
On Unix it might be necessary to set the environment variable TCLLIBPATH
in order for this to work.
If you just built Snack and the sample extension you use this command

setenv TCLLIBPATH "~/snack2.1.6/unix ~/snack2.1.6/ext $TCLLIBPATH"

Note that the list of directories is space separated.

Changes to snack/ext/square.dsp.

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
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







-
+









-
+














-
+









-
+







# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SQUARE_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "C:\Program Files\Tcl\include" /I "../generic" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SQUARE_EXPORTS" /D "USE_SNACK_STUBS" /D "USE_TCL_STUBS" /D "WIN" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "C:\Tcl\include" /I "../generic" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SQUARE_EXPORTS" /D "USE_SNACK_STUBS" /D "USE_TCL_STUBS" /D "WIN" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib snackstub20.lib tclstub83.lib /nologo /dll /machine:I386 /nodefaultlib:"libc.lib" /nodefaultlib:"msvcrt.lib" /out:"libsquare.dll" /libpath:"C:\Program Files\Tcl\lib" /libpath:"C:\Program Files\Tcl\lib\snack2.0\"
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib snackstub21.lib tclstub83.lib /nologo /dll /machine:I386 /nodefaultlib:"libc.lib" /nodefaultlib:"msvcrt.lib" /out:"libsquare.dll" /libpath:"C:\Tcl\lib" /libpath:"C:\Tcl\lib\snack2.1\"

!ELSEIF  "$(CFG)" == "square - Win32 Debug"

# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SQUARE_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "C:\Program Files\Tcl\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SQUARE_EXPORTS" /D "USE_SNACK_STUBS" /D "USE_TCL_STUBS" /D "USE_TK_STUBS" /D "WIN" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "C:\Tcl\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SQUARE_EXPORTS" /D "USE_SNACK_STUBS" /D "USE_TCL_STUBS" /D "USE_TK_STUBS" /D "WIN" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib snackstub20.lib tclstub83.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /out:"libsquare.dll" /out:"libsquare.dll" /libpath:"C:\Program Files\Tcl\lib" /libpath:"..\win\Debug"
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib snackstub21.lib tclstub83.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /out:"libsquare.dll" /out:"libsquare.dll" /libpath:"C:\Tcl\lib" /libpath:"..\win\Debug"

!ENDIF 

# Begin Target

# Name "square - Win32 Release"
# Name "square - Win32 Debug"

Added snack/generic/SnackOgg.c.


















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































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
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#include <math.h>
#include <vorbis/codec.h>
#include <vorbis/vorbisenc.h>
#include <tcl.h>
#include "snack.h"
#include <stdlib.h>
#include <time.h>

#if defined(__WIN32__)
#  include <io.h>
#  include <fcntl.h>
#  define WIN32_LEAN_AND_MEAN
#  include <windows.h>
#  undef WIN32_LEAN_AND_MEAN
#  define EXPORT(a,b) __declspec(dllexport) a b
BOOL APIENTRY
DllMain(HINSTANCE hInst, DWORD reason, LPVOID reserved)
{
  return TRUE;
}
#else
#  define EXPORT(a,b) a b
#endif


/* vorbisfile.h */

/* The function prototypes for the callbacks are basically the same as for
 * the stdio functions fread, fseek, fclose, ftell. 
 * The one difference is that the FILE * arguments have been replaced with
 * a void * - this is to be used as a pointer to whatever internal data these
 * functions might need. In the stdio case, it's just a FILE * cast to a void *
 * 
 * If you use other functions, check the docs for these functions and return
 * the right values. For seek_func(), you *MUST* return -1 if the stream is
 * unseekable
 */
typedef struct {
  size_t (*read_func)  (void *ptr, size_t size, size_t nmemb, void *datasource);
  int    (*seek_func)  (void *datasource, ogg_int64_t offset, int whence);
  int    (*close_func) (void *datasource);
  long   (*tell_func)  (void *datasource);
} ov_callbacks;


typedef struct OggVorbis_File {
  Tcl_Channel             datasource; /* Pointer to a FILE *, etc. */
  int              seekable;
  ogg_int64_t          offset;
  ogg_int64_t          end;
  ogg_sync_state   oy; 

  /* If the FILE handle isn't seekable (eg, a pipe), only the current
     stream appears */
  int              links;
  ogg_int64_t          *offsets;
  ogg_int64_t          *dataoffsets;
  long             *serialnos;
  ogg_int64_t          *pcmlengths;
  vorbis_info      *vi;
  vorbis_comment   *vc;

  /* Decoding working state local storage */
  ogg_int64_t          pcm_offset;
  int              decode_ready;
  long             current_serialno;
  int              current_link;

  double           bittrack;
  double           samptrack;

  ogg_stream_state os; /* take physical pages, weld into a logical
                          stream of packets */
  vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
  vorbis_block     vb; /* local working space for packet->PCM decode */

  ov_callbacks callbacks;

  int maxbitrate;
  int minbitrate;
  int nombitrate;
  Tcl_Obj *commList;

} OggVorbis_File;

int ov_clear(Tcl_Interp *interp, OggVorbis_File *vf);
int ov_open(Tcl_Interp *interp, Tcl_Channel *f, OggVorbis_File *vf,
	    char *initial,long ibytes);
int ov_open_callbacks(Tcl_Interp *interp, Tcl_Channel *datasource,
		      OggVorbis_File *vf,char *initial,
		      long ibytes, ov_callbacks callbacks);

long ov_bitrate(OggVorbis_File *vf,int i);
long ov_bitrate_instant(OggVorbis_File *vf);
long ov_streams(OggVorbis_File *vf);
long ov_seekable(OggVorbis_File *vf);
long ov_serialnumber(OggVorbis_File *vf,int i);

ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i);
ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i);
double ov_time_total(OggVorbis_File *vf,int i);

int ov_raw_seek(OggVorbis_File *vf,long pos);
int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos);
int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos);
int ov_time_seek(OggVorbis_File *vf,double pos);
int ov_time_seek_page(OggVorbis_File *vf,double pos);

ogg_int64_t ov_raw_tell(OggVorbis_File *vf);
ogg_int64_t ov_pcm_tell(OggVorbis_File *vf);
double ov_time_tell(OggVorbis_File *vf);

vorbis_info *ov_info(OggVorbis_File *vf,int link);
vorbis_comment *ov_comment(OggVorbis_File *vf,int link);

long ov_read(OggVorbis_File *vf,char *buffer,int length,
		    int bigendianp,int word,int sgned,int *bitstream);

/* vorbisfile.c */

/********************************************************************
 *                                                                  *
 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
 *                                                                  *
 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001             *
 * by the XIPHOPHORUS Company http://www.xiph.org/                  *

 ********************************************************************

 function: stdio-based convenience library for opening/seeking/decoding
 last mod: $Id: vorbisfile.c,v 1.41 2001/02/26 03:50:43 xiphmont Exp $

 ********************************************************************/

#include <stdio.h>
#include <errno.h>
#include <string.h>

/* misc.h */
extern void *_vorbis_block_alloc(vorbis_block *vb,long bytes);
extern void _vorbis_block_ripcord(vorbis_block *vb);
extern void _analysis_output(char *base,int i,float *v,int n,int bark,int dB);

#ifdef DEBUG_LEAKS
extern void *_VDBG_malloc(void *ptr,long bytes,char *file,long line); 
extern void _VDBG_free(void *ptr,char *file,long line); 

#ifndef MISC_C 
#undef _ogg_malloc
#undef _ogg_calloc
#undef _ogg_realloc
#undef _ogg_free

#define _ogg_malloc(x) _VDBG__ogg_malloc(NULL,(x),__FILE__,__LINE__)
#define _ogg_calloc(x,y) _VDBG__ogg_malloc(NULL,(x)*(y),__FILE__,__LINE__)
#define _ogg_realloc(x,y) _VDBG__ogg_malloc((x),(y),__FILE__,__LINE__)
#define _ogg_free(x) _VDBG__ogg_free((x),__FILE__,__LINE__)
#endif
#endif

/* os.h */
#include <ogg/os_types.h>

#ifndef _V_IFDEFJAIL_H_
#  define _V_IFDEFJAIL_H_

#  ifdef __GNUC__
#    define STIN static inline
#  elif _WIN32
#    define STIN static __inline
#else
#  define STIN static
#endif

#ifndef M_PI
#  define M_PI (3.1415926536f)
#endif

#ifdef _WIN32
#  include <malloc.h>
#  define rint(x)   (floor((x)+0.5f)) 
#  define NO_FLOAT_MATH_LIB
#  define FAST_HYPOT(a, b) sqrt((a)*(a) + (b)*(b))
#endif

#ifndef __GNUC__
#  define NO_FLOAT_MATH_LIB
#endif

#ifdef DARWIN
#  define NO_FLOAT_MATH_LIB
#endif

#ifndef NO_FLOAT_MATH_LIB
#  define sqrt sqrtf
#  define log logf
#  define exp expf
#  define pow powf
#  define acos acosf
#  define atan atanf
#  define frexp frexpf
#  define rint rintf
#endif


#ifndef FAST_HYPOT
#  define FAST_HYPOT hypot
#endif

#endif

#ifdef HAVE_ALLOCA_H
#  include <alloca.h>
#endif

#ifdef USE_MEMORY_H
#  include <memory.h>
#endif

#ifndef min
#  define min(x,y)  ((x)>(y)?(y):(x))
#endif

#ifndef max
#  define max(x,y)  ((x)<(y)?(y):(x))
#endif

#if defined(__i386__) && defined(__GNUC__) && !defined(__BEOS__)
#  define VORBIS_FPU_CONTROL
/* both GCC and MSVC are kinda stupid about rounding/casting to int.
   Because of encapsulation constraints (GCC can't see inside the asm
   block and so we end up doing stupid things like a store/load that
   is collectively a noop), we do it this way */

/* we must set up the fpu before this works!! */

typedef ogg_int16_t vorbis_fpu_control;

static inline void vorbis_fpu_setround(vorbis_fpu_control *fpu){
  ogg_int16_t ret;
  ogg_int16_t temp;
  __asm__ __volatile__("fnstcw %0\n\t"
         "movw %0,%%dx\n\t"
         "orw $62463,%%dx\n\t"
         "movw %%dx,%1\n\t"
         "fldcw %1\n\t":"=m"(ret):"m"(temp): "dx");
  *fpu=ret;
}

static inline void vorbis_fpu_restore(vorbis_fpu_control fpu){
  __asm__ __volatile__("fldcw %0":: "m"(fpu));
}

/* assumes the FPU is in round mode! */
static inline int vorbis_ftoi(double f){  /* yes, double!  Otherwise,
                                             we get extra fst/fld to
                                             truncate precision */
  int i;
  __asm__("fistl %0": "=m"(i) : "t"(f));
  return(i);
}
#endif


#if defined(_WIN32) && !defined(__GNUC__)
#  define VORBIS_FPU_CONTROL

typedef ogg_int16_t vorbis_fpu_control;

static __inline int vorbis_ftoi(double f){
       int i;
       __asm{
        fld f
        fistp i
       }
       return i;
}

static __inline void vorbis_fpu_setround(vorbis_fpu_control *fpu){
}

static __inline void vorbis_fpu_restore(vorbis_fpu_control fpu){
}

#endif


#ifndef VORBIS_FPU_CONTROL

typedef int vorbis_fpu_control;

static int vorbis_ftoi(double f){
  return (int)(f+.5);
}

/* We don't have special code for this compiler/arch, so do it the slow way */
#  define vorbis_fpu_setround(vorbis_fpu_control) {}
#  define vorbis_fpu_restore(vorbis_fpu_control) {}

#endif

/* A 'chained bitstream' is a Vorbis bitstream that contains more than
   one logical bitstream arranged end to end (the only form of Ogg
   multiplexing allowed in a Vorbis bitstream; grouping [parallel
   multiplexing] is not allowed in Vorbis) */

/* A Vorbis file can be played beginning to end (streamed) without
   worrying ahead of time about chaining (see decoder_example.c).  If
   we have the whole file, however, and want random access
   (seeking/scrubbing) or desire to know the total length/time of a
   file, we need to account for the possibility of chaining. */

/* We can handle things a number of ways; we can determine the entire
   bitstream structure right off the bat, or find pieces on demand.
   This example determines and caches structure for the entire
   bitstream, but builds a virtual decoder on the fly when moving
   between links in the chain. */

/* There are also different ways to implement seeking.  Enough
   information exists in an Ogg bitstream to seek to
   sample-granularity positions in the output.  Or, one can seek by
   picking some portion of the stream roughly in the desired area if
   we only want course navigation through the stream. */

/*************************************************************************
 * Many, many internal helpers.  The intention is not to be confusing; 
 * rampant duplication and monolithic function implementation would be 
 * harder to understand anyway.  The high level functions are last.  Begin
 * grokking near the end of the file */

/* read a little more data from the file/pipe into the ogg_sync framer */
#define CHUNKSIZE 4096
static long _get_data(OggVorbis_File *vf){
  errno=0;
  if(vf->datasource){
    char *buffer=ogg_sync_buffer(&vf->oy,CHUNKSIZE);
  /*long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource);*/
    long bytes=Tcl_Read(vf->datasource,buffer,CHUNKSIZE);
    if(bytes>0)ogg_sync_wrote(&vf->oy,bytes);
    if(bytes==0 && errno)return(-1);
    return(bytes);
  }else
    return(0);
}

/* save a tiny smidge of verbosity to make the code more readable */
static void _seek_helper(OggVorbis_File *vf,long offset){
  if(vf->datasource){
    Tcl_Seek(vf->datasource, offset, SEEK_SET); 
    /*    (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET);*/
    vf->offset=offset;
    ogg_sync_reset(&vf->oy);
  }else{
    /* shouldn't happen unless someone writes a broken callback */
    return;
  }
}

/* The read/seek functions track absolute position within the stream */

/* from the head of the stream, get the next page.  boundary specifies
   if the function is allowed to fetch more data from the stream (and
   how much) or only use internally buffered data.

   boundary: -1) unbounded search
              0) read no additional data; use cached only
	      n) search for a new page beginning for n bytes

   return:   <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)
              n) found a page at absolute offset n */

static long _get_next_page(OggVorbis_File *vf,ogg_page *og,int boundary){
  if(boundary>0)boundary+=vf->offset;
  while(1){
    long more;

    if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);
    more=ogg_sync_pageseek(&vf->oy,og);
    
    if(more<0){
      /* skipped n bytes */
      vf->offset-=more;
    }else{
      if(more==0){
	/* send more paramedics */
	if(!boundary)return(OV_FALSE);
	{
	  long ret=_get_data(vf);
	  if(ret==0)return(OV_EOF);
	  if(ret<0)return(OV_EREAD);
	}
      }else{
	/* got a page.  Return the offset at the page beginning,
           advance the internal offset past the page end */
	long ret=vf->offset;
	vf->offset+=more;
	return(ret);
	
      }
    }
  }
}

/* find the latest page beginning before the current stream cursor
   position. Much dirtier than the above as Ogg doesn't have any
   backward search linkage.  no 'readp' as it will certainly have to
   read. */
/* returns offset or OV_EREAD, OV_FAULT */
static long _get_prev_page(OggVorbis_File *vf,ogg_page *og){
  long begin=vf->offset;
  long ret;
  int offset=-1;

  while(offset==-1){
    begin-=CHUNKSIZE;
    _seek_helper(vf,begin);
    while(vf->offset<begin+CHUNKSIZE){
      ret=_get_next_page(vf,og,begin+CHUNKSIZE-vf->offset);
      if(ret==OV_EREAD)return(OV_EREAD);
      if(ret<0){
	break;
      }else{
	offset=ret;
      }
    }
  }

  /* we have the offset.  Actually snork and hold the page now */
  _seek_helper(vf,offset);
  ret=_get_next_page(vf,og,CHUNKSIZE);
  if(ret<0)
    /* this shouldn't be possible */
    return(OV_EFAULT);

  return(offset);
}

/* finds each bitstream link one at a time using a bisection search
   (has to begin by knowing the offset of the lb's initial page).
   Recurses for each link so it can alloc the link storage after
   finding them all, then unroll and fill the cache at the same time */
static int _bisect_forward_serialno(OggVorbis_File *vf,
				    long begin,
				    long searched,
				    long end,
				    long currentno,
				    long m){
  long endsearched=end;
  long next=end;
  ogg_page og;
  long ret;
  
  /* the below guards against garbage seperating the last and
     first pages of two links. */
  while(searched<endsearched){
    long bisect;
    
    if(endsearched-searched<CHUNKSIZE){
      bisect=searched;
    }else{
      bisect=(searched+endsearched)/2;
    }
    
    _seek_helper(vf,bisect);
    ret=_get_next_page(vf,&og,-1);
    if(ret==OV_EREAD)return(OV_EREAD);
    if(ret<0 || ogg_page_serialno(&og)!=currentno){
      endsearched=bisect;
      if(ret>=0)next=ret;
    }else{
      searched=ret+og.header_len+og.body_len;
    }
  }

  _seek_helper(vf,next);
  ret=_get_next_page(vf,&og,-1);
  if(ret==OV_EREAD)return(OV_EREAD);
  
  if(searched>=end || ret<0){
    vf->links=m+1;
    vf->offsets=_ogg_malloc((m+2)*sizeof(ogg_int64_t));
    vf->offsets[m+1]=searched;
  }else{
    ret=_bisect_forward_serialno(vf,next,vf->offset,
				 end,ogg_page_serialno(&og),m+1);
    if(ret==OV_EREAD)return(OV_EREAD);
  }
  
  vf->offsets[m]=begin;
  return(0);
}

/* uses the local ogg_stream storage in vf; this is important for
   non-streaming input sources */
static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
			  long *serialno,ogg_page *og_ptr){
  ogg_page og;
  ogg_packet op;
  int i,ret=0;
  
  if(!og_ptr){
    ret=_get_next_page(vf,&og,CHUNKSIZE);
    if(ret==OV_EREAD)return(OV_EREAD);
    if(ret<0)return OV_ENOTVORBIS;
    og_ptr=&og;
  }

  if(serialno)*serialno=ogg_page_serialno(og_ptr);
  ogg_stream_init(&vf->os,ogg_page_serialno(og_ptr));
  
  /* extract the initial header from the first page and verify that the
     Ogg bitstream is in fact Vorbis data */
  
  vorbis_info_init(vi);
  vorbis_comment_init(vc);
  
  i=0;
  while(i<3){
    ogg_stream_pagein(&vf->os,og_ptr);
    while(i<3){
      int result=ogg_stream_packetout(&vf->os,&op);
      if(result==0)break;
      if(result==-1){
	ret=OV_EBADHEADER;
	goto bail_header;
      }
      if((ret=vorbis_synthesis_headerin(vi,vc,&op))){
	goto bail_header;
      }
      i++;
    }
    if(i<3)
      if(_get_next_page(vf,og_ptr,1)<0){
	ret=OV_EBADHEADER;
	goto bail_header;
      }
  }
  return 0; 

 bail_header:
  vorbis_info_clear(vi);
  vorbis_comment_clear(vc);
  ogg_stream_clear(&vf->os);
  return ret;
}

/* last step of the OggVorbis_File initialization; get all the
   vorbis_info structs and PCM positions.  Only called by the seekable
   initialization (local stream storage is hacked slightly; pay
   attention to how that's done) */

/* this is void and does not propogate errors up because we want to be
   able to open and use damaged bitstreams as well as we can.  Just
   watch out for missing information for links in the OggVorbis_File
   struct */
static void _prefetch_all_headers(OggVorbis_File *vf,vorbis_info *first_i,
				  vorbis_comment *first_c,
				  long dataoffset){
  ogg_page og;
  int i,ret;
  
  vf->vi=_ogg_calloc(vf->links,sizeof(vorbis_info));
  vf->vc=_ogg_calloc(vf->links,sizeof(vorbis_info));
  vf->dataoffsets=_ogg_malloc(vf->links*sizeof(ogg_int64_t));
  vf->pcmlengths=_ogg_malloc(vf->links*sizeof(ogg_int64_t));
  vf->serialnos=_ogg_malloc(vf->links*sizeof(long));
  
  for(i=0;i<vf->links;i++){
    if(first_i && first_c && i==0){
      /* we already grabbed the initial header earlier.  This just
         saves the waste of grabbing it again */
      memcpy(vf->vi+i,first_i,sizeof(vorbis_info));
      memcpy(vf->vc+i,first_c,sizeof(vorbis_comment));
      vf->dataoffsets[i]=dataoffset;
    }else{

      /* seek to the location of the initial header */

      _seek_helper(vf,vf->offsets[i]);
      if(_fetch_headers(vf,vf->vi+i,vf->vc+i,NULL,NULL)<0){
    	vf->dataoffsets[i]=-1;
      }else{
	vf->dataoffsets[i]=vf->offset;
        ogg_stream_clear(&vf->os);
      }
    }

    /* get the serial number and PCM length of this link. To do this,
       get the last page of the stream */
    {
      long end=vf->offsets[i+1];
      _seek_helper(vf,end);

      while(1){
	ret=_get_prev_page(vf,&og);
	if(ret<0){
	  /* this should not be possible, actually */
	  vorbis_info_clear(vf->vi+i);
	  vorbis_comment_clear(vf->vc+i);
	  break;
	}
	if(ogg_page_granulepos(&og)!=-1){
	  vf->serialnos[i]=ogg_page_serialno(&og);
	  vf->pcmlengths[i]=ogg_page_granulepos(&og);
	  break;
	}
      }
    }
  }
}

static void _make_decode_ready(OggVorbis_File *vf){
  if(vf->decode_ready)return;
  if(vf->seekable){
    vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link);
  }else{
    vorbis_synthesis_init(&vf->vd,vf->vi);
  }    
  vorbis_block_init(&vf->vd,&vf->vb);
  vf->decode_ready=1;
  return;
}

static int _open_seekable(OggVorbis_File *vf){
  vorbis_info initial_i;
  vorbis_comment initial_c;
  long serialno,end;
  int ret;
  long dataoffset;
  ogg_page og;
  
  /* is this even vorbis...? */
  ret=_fetch_headers(vf,&initial_i,&initial_c,&serialno,NULL);
  dataoffset=vf->offset;
  ogg_stream_clear(&vf->os);
  if(ret<0)return(ret);
  
  /* we can seek, so set out learning all about this file */
  vf->seekable=1;
  Tcl_Seek(vf->datasource, 0, SEEK_END); 
  /*  (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
  vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);*/
  vf->offset=vf->end=Tcl_Tell(vf->datasource);

  /* We get the offset for the last page of the physical bitstream.
     Most OggVorbis files will contain a single logical bitstream */
  end=_get_prev_page(vf,&og);
  if(end<0){
    ogg_stream_clear(&vf->os);
    return(end);
  }

  /* more than one logical bitstream? */
  if(ogg_page_serialno(&og)!=serialno){

    /* Chained bitstream. Bisect-search each logical bitstream
       section.  Do so based on serial number only */
    if(_bisect_forward_serialno(vf,0,0,end+1,serialno,0)<0){
      ogg_stream_clear(&vf->os);
      return(OV_EREAD);
    }

  }else{

    /* Only one logical bitstream */
    if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0)){
      ogg_stream_clear(&vf->os);
      return(OV_EREAD);
    }

  }

  _prefetch_all_headers(vf,&initial_i,&initial_c,dataoffset);
  return(ov_raw_seek(vf,0));

}

static int _open_nonseekable(OggVorbis_File *vf){
  int ret;
  /* we cannot seek. Set up a 'single' (current) logical bitstream entry  */
  vf->links=1;
  vf->vi=_ogg_calloc(vf->links,sizeof(vorbis_info));
  vf->vc=_ogg_calloc(vf->links,sizeof(vorbis_info));

  /* Try to fetch the headers, maintaining all the storage */
  if((ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,NULL))<0)
    return(ret);
  _make_decode_ready(vf);

  return 0;
}

/* clear out the current logical bitstream decoder */ 
static void _decode_clear(OggVorbis_File *vf){
  ogg_stream_clear(&vf->os);
  vorbis_dsp_clear(&vf->vd);
  vorbis_block_clear(&vf->vb);
  vf->decode_ready=0;

  vf->bittrack=0.f;
  vf->samptrack=0.f;
}

/* fetch and process a packet.  Handles the case where we're at a
   bitstream boundary and dumps the decoding machine.  If the decoding
   machine is unloaded, it loads it.  It also keeps pcm_offset up to
   date (seek and read both use this.  seek uses a special hack with
   readp). 

   return: <0) error, OV_HOLE (lost packet) or OV_EOF
            0) need more data (only if readp==0)
	    1) got a packet 
*/

static int _process_packet(OggVorbis_File *vf,int readp){
  ogg_page og;

  /* handle one packet.  Try to fetch it from current stream state */
  /* extract packets from page */
  while(1){
    
    /* process a packet if we can.  If the machine isn't loaded,
       neither is a page */
    if(vf->decode_ready){
      ogg_packet op;
      int result=ogg_stream_packetout(&vf->os,&op);
      ogg_int64_t granulepos;
      
      if(result==-1)return(OV_HOLE); /* hole in the data. */
      if(result>0){
	/* got a packet.  process it */
	granulepos=op.granulepos;
	if(!vorbis_synthesis(&vf->vb,&op)){ /* lazy check for lazy
                                               header handling.  The
                                               header packets aren't
                                               audio, so if/when we
                                               submit them,
                                               vorbis_synthesis will
                                               reject them */

	  /* suck in the synthesis data and track bitrate */
	  {
	    int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);
	    vorbis_synthesis_blockin(&vf->vd,&vf->vb);
	    vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;
	    vf->bittrack+=op.bytes*8;
	  }
	  
	  /* update the pcm offset. */
	  if(granulepos!=-1 && !op.e_o_s){
	    int link=(vf->seekable?vf->current_link:0);
	    int i,samples;
	    
	    /* this packet has a pcm_offset on it (the last packet
	       completed on a page carries the offset) After processing
	       (above), we know the pcm position of the *last* sample
	       ready to be returned. Find the offset of the *first*

	       As an aside, this trick is inaccurate if we begin
	       reading anew right at the last page; the end-of-stream
	       granulepos declares the last frame in the stream, and the
	       last packet of the last page may be a partial frame.
	       So, we need a previous granulepos from an in-sequence page
	       to have a reference point.  Thus the !op.e_o_s clause
	       above */
	    
	    samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
	    
	    granulepos-=samples;
	    for(i=0;i<link;i++)
	      granulepos+=vf->pcmlengths[i];
	    vf->pcm_offset=granulepos;
	  }
	  return(1);
	}
      }
    }

    if(!readp)return(0);
    if(_get_next_page(vf,&og,-1)<0)return(OV_EOF); /* eof. leave unitialized */

    /* bitrate tracking; add the header's bytes here, the body bytes
       are done by packet above */
    vf->bittrack+=og.header_len*8;

    /* has our decoding just traversed a bitstream boundary? */
    if(vf->decode_ready){
      if(vf->current_serialno!=ogg_page_serialno(&og)){
	_decode_clear(vf);
      }
    }

    /* Do we need to load a new machine before submitting the page? */
    /* This is different in the seekable and non-seekable cases.  

       In the seekable case, we already have all the header
       information loaded and cached; we just initialize the machine
       with it and continue on our merry way.

       In the non-seekable (streaming) case, we'll only be at a
       boundary if we just left the previous logical bitstream and
       we're now nominally at the header of the next bitstream
    */

    if(!vf->decode_ready){
      int link;
      if(vf->seekable){
	vf->current_serialno=ogg_page_serialno(&og);
	
	/* match the serialno to bitstream section.  We use this rather than
	   offset positions to avoid problems near logical bitstream
	   boundaries */
	for(link=0;link<vf->links;link++)
	  if(vf->serialnos[link]==vf->current_serialno)break;
	if(link==vf->links)return(OV_EBADLINK); /* sign of a bogus
						   stream.  error out,
						   leave machine
						   uninitialized */
	
	vf->current_link=link;
	
	ogg_stream_init(&vf->os,vf->current_serialno);
	ogg_stream_reset(&vf->os); 
	
      }else{
	/* we're streaming */
	/* fetch the three header packets, build the info struct */
	
	_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,&og);
	vf->current_link++;
	link=0;
      }
      
      _make_decode_ready(vf);
    }
    ogg_stream_pagein(&vf->os,&og);
  }
}

/**********************************************************************
 * The helpers are over; it's all toplevel interface from here on out */
 
/* clear out the OggVorbis_File struct */
int ov_clear(Tcl_Interp *interp,OggVorbis_File *vf){
  if(vf){
    vorbis_block_clear(&vf->vb);
    vorbis_dsp_clear(&vf->vd);
    ogg_stream_clear(&vf->os);
    
    if(vf->vi && vf->links){
      int i;
      for(i=0;i<vf->links;i++){
	vorbis_info_clear(vf->vi+i);
	vorbis_comment_clear(vf->vc+i);
      }
      _ogg_free(vf->vi);
      _ogg_free(vf->vc);
    }
    if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
    if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
    if(vf->serialnos)_ogg_free(vf->serialnos);
    if(vf->offsets)_ogg_free(vf->offsets);
    ogg_sync_clear(&vf->oy);
    /*    if(vf->datasource)(vf->callbacks.close_func)(vf->datasource);*/
    if(vf->datasource)Tcl_Close(interp,vf->datasource);
    memset(vf,0,sizeof(OggVorbis_File)-4*sizeof(int));
  }
#ifdef DEBUG_LEAKS
  _VDBG_dump();
#endif
  return(0);
}

static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){
  if(f==NULL)return(-1);
  return fseek(f,(int)off,whence);
}

/* inspects the OggVorbis file and finds/documents all the logical
   bitstreams contained in it.  Tries to be tolerant of logical
   bitstream sections that are truncated/woogie. 

   return: -1) error
            0) OK
*/

int ov_open(Tcl_Interp *interp,Tcl_Channel *f,OggVorbis_File *vf,
	    char *initial,long ibytes){
  ov_callbacks callbacks = {
    (size_t (*)(void *, size_t, size_t, void *))  fread,
    (int (*)(void *, ogg_int64_t, int))              _fseek64_wrap,
    (int (*)(void *))                             fclose,
    (long (*)(void *))                            ftell
  };

  return ov_open_callbacks(interp, f, vf, initial, ibytes, callbacks);
}
  

int ov_open_callbacks(Tcl_Interp *interp,Tcl_Channel *f,OggVorbis_File *vf,
		      char *initial,long ibytes, ov_callbacks callbacks)
{
  long offset=(f?Tcl_Seek(*f,0,SEEK_CUR):-1); 
  /*  long offset=(f?callbacks.seek_func(f,0,SEEK_CUR):-1);*/
  int ret;

  memset(vf,0,sizeof(OggVorbis_File)-4*sizeof(int));
  vf->datasource=*f;
  vf->callbacks = callbacks;

  /* init the framing state */
  ogg_sync_init(&vf->oy);

  /* perhaps some data was previously read into a buffer for testing
     against other stream types.  Allow initialization from this
     previously read data (as we may be reading from a non-seekable
     stream) */
  if(initial){
    char *buffer=ogg_sync_buffer(&vf->oy,ibytes);
    memcpy(buffer,initial,ibytes);
    ogg_sync_wrote(&vf->oy,ibytes);
  }

  /* can we seek? Stevens suggests the seek test was portable */
  if(offset!=-1){
    ret=_open_seekable(vf);
  }else{
    ret=_open_nonseekable(vf);
  }
  if(ret){
    vf->datasource=NULL;
    ov_clear(interp,vf);
  }
  return(ret);
}

/* How many logical bitstreams in this physical bitstream? */
long ov_streams(OggVorbis_File *vf){
  return vf->links;
}

/* Is the FILE * associated with vf seekable? */
long ov_seekable(OggVorbis_File *vf){
  return vf->seekable;
}

/* returns the bitrate for a given logical bitstream or the entire
   physical bitstream.  If the file is open for random access, it will
   find the *actual* average bitrate.  If the file is streaming, it
   returns the nominal bitrate (if set) else the average of the
   upper/lower bounds (if set) else -1 (unset).

   If you want the actual bitrate field settings, get them from the
   vorbis_info structs */

long ov_bitrate(OggVorbis_File *vf,int i){
  if(i>=vf->links)return(OV_EINVAL);
  if(!vf->seekable && i!=0)return(ov_bitrate(vf,0));
  if(i<0){
    ogg_int64_t bits=0;
    int i;
    for(i=0;i<vf->links;i++)
      bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8;
    return(rint(bits/ov_time_total(vf,-1)));
  }else{
    if(vf->seekable){
      /* return the actual bitrate */
      return(rint((vf->offsets[i+1]-vf->dataoffsets[i])*8/ov_time_total(vf,i)));
    }else{
      /* return nominal if set */
      if(vf->vi[i].bitrate_nominal>0){
	return vf->vi[i].bitrate_nominal;
      }else{
	if(vf->vi[i].bitrate_upper>0){
	  if(vf->vi[i].bitrate_lower>0){
	    return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2;
	  }else{
	    return vf->vi[i].bitrate_upper;
	  }
	}
	return(OV_FALSE);
      }
    }
  }
}

/* returns the actual bitrate since last call.  returns -1 if no
   additional data to offer since last call (or at beginning of stream) */
long ov_bitrate_instant(OggVorbis_File *vf){
  int link=(vf->seekable?vf->current_link:0);
  long ret;
  if(vf->samptrack==0)return(OV_FALSE);
  ret=vf->bittrack/vf->samptrack*vf->vi[link].rate+.5;
  vf->bittrack=0.f;
  vf->samptrack=0.f;
  return(ret);
}

/* Guess */
long ov_serialnumber(OggVorbis_File *vf,int i){
  if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1));
  if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1));
  if(i<0){
    return(vf->current_serialno);
  }else{
    return(vf->serialnos[i]);
  }
}

/* returns: total raw (compressed) length of content if i==-1
            raw (compressed) length of that logical bitstream for i==0 to n
	    -1 if the stream is not seekable (we can't know the length)
*/
ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){
  if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
  if(i<0){
    long acc=0;
    int i;
    for(i=0;i<vf->links;i++)
      acc+=ov_raw_total(vf,i);
    return(acc);
  }else{
    return(vf->offsets[i+1]-vf->offsets[i]);
  }
}

/* returns: total PCM length (samples) of content if i==-1
            PCM length (samples) of that logical bitstream for i==0 to n
	    -1 if the stream is not seekable (we can't know the length)
*/
ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){
  if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
  if(i<0){
    ogg_int64_t acc=0;
    int i;
    for(i=0;i<vf->links;i++)
      acc+=ov_pcm_total(vf,i);
    return(acc);
  }else{
    return(vf->pcmlengths[i]);
  }
}

/* returns: total seconds of content if i==-1
            seconds in that logical bitstream for i==0 to n
	    -1 if the stream is not seekable (we can't know the length)
*/
double ov_time_total(OggVorbis_File *vf,int i){
  if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
  if(i<0){
    double acc=0;
    int i;
    for(i=0;i<vf->links;i++)
      acc+=ov_time_total(vf,i);
    return(acc);
  }else{
    return((float)(vf->pcmlengths[i])/vf->vi[i].rate);
  }
}

/* seek to an offset relative to the *compressed* data. This also
   immediately sucks in and decodes pages to update the PCM cursor. It
   will cross a logical bitstream boundary, but only if it can't get
   any packets out of the tail of the bitstream we seek to (so no
   surprises). 

   returns zero on success, nonzero on failure */

int ov_raw_seek(OggVorbis_File *vf,long pos){
  int flag=0;
  if(!vf->seekable)return(OV_ENOSEEK); /* don't dump machine if we can't seek */
  if(pos<0 || pos>vf->offsets[vf->links])return(OV_EINVAL);

  /* clear out decoding machine state */
  vf->pcm_offset=-1;
  _decode_clear(vf);
  
  /* seek */
  _seek_helper(vf,pos);

  /* we need to make sure the pcm_offset is set.  We use the
     _fetch_packet helper to process one packet with readp set, then
     call it until it returns '0' with readp not set (the last packet
     from a page has the 'granulepos' field set, and that's how the
     helper updates the offset */

  while(!flag){
    switch(_process_packet(vf,1)){
    case 0:case OV_EOF:
      /* oh, eof. There are no packets remaining.  Set the pcm offset to
	 the end of file */
      vf->pcm_offset=ov_pcm_total(vf,-1);
      return(0);
    case OV_HOLE:
      break;
    case OV_EBADLINK:
      goto seek_error;
    default:
      /* all OK */
      flag=1;
      break;
    }
  }
  
  while(1){
    /* don't have to check each time through for the updated granule;
       it's always the last complete packet on a page */
    switch(_process_packet(vf,0)){
    case 0:case OV_EOF:
      /* the offset is set unless it's a bogus bitstream with no
         offset information but that's not our fault.  We still run
         gracefully, we're just missing the offset */
      return(0);
    case OV_EBADLINK:
      goto seek_error;
    default:
      /* continue processing packets */
      break;
    }
  }
  
 seek_error:
  /* dump the machine so we're in a known state */
  vf->pcm_offset=-1;
  _decode_clear(vf);
  return OV_EBADLINK;
}

/* Page granularity seek (faster than sample granularity because we
   don't do the last bit of decode to find a specific sample).

   Seek to the last [granule marked] page preceeding the specified pos
   location, such that decoding past the returned point will quickly
   arrive at the requested position. */
int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
  int link=-1;
  long ret;
  ogg_int64_t total=ov_pcm_total(vf,-1);

  if(!vf->seekable)return(OV_ENOSEEK);
  if(pos<0 || pos>total)return(OV_EINVAL);

  /* which bitstream section does this pcm offset occur in? */
  for(link=vf->links-1;link>=0;link--){
    total-=vf->pcmlengths[link];
    if(pos>=total)break;
  }

  /* search within the logical bitstream for the page with the highest
     pcm_pos preceeding (or equal to) pos.  There is a danger here;
     missing pages or incorrect frame number information in the
     bitstream could make our task impossible.  Account for that (it
     would be an error condition) */
  {
    ogg_int64_t target=pos-total;
    long end=vf->offsets[link+1];
    long begin=vf->offsets[link];
    long best=begin;

    ogg_page og;
    while(begin<end){
      long bisect;
    
      if(end-begin<CHUNKSIZE){
	bisect=begin;
      }else{
	bisect=(end+begin)/2;
      }
    
      _seek_helper(vf,bisect);
      ret=_get_next_page(vf,&og,end-bisect);
      switch(ret){
      case OV_FALSE: case OV_EOF:
	end=bisect;
	break;
      case OV_EREAD:
	goto seek_error;
      default:
	{
	  ogg_int64_t granulepos=ogg_page_granulepos(&og);
	  if(granulepos<target){
	    best=ret;  /* raw offset of packet with granulepos */ 
	    begin=vf->offset; /* raw offset of next packet */
	  }else{
	    end=bisect;
	  }
	}
      }
    }

    /* found our page. seek to it (call raw_seek). */
    
    if((ret=ov_raw_seek(vf,best)))goto seek_error;
  }
  
  /* verify result */
  if(vf->pcm_offset>=pos || pos>ov_pcm_total(vf,-1)){
    ret=OV_EFAULT;
    goto seek_error;
  }
  return(0);
  
 seek_error:
  /* dump machine so we're in a known state */
  vf->pcm_offset=-1;
  _decode_clear(vf);
  return ret;
}

/* seek to a sample offset relative to the decompressed pcm stream 
   returns zero on success, nonzero on failure */

int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
  int ret=ov_pcm_seek_page(vf,pos);
  if(ret<0)return(ret);
  
  /* discard samples until we reach the desired position. Crossing a
     logical bitstream boundary with abandon is OK. */
  while(vf->pcm_offset<pos){
    float **pcm;
    long target=pos-vf->pcm_offset;
    long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);

    if(samples>target)samples=target;
    vorbis_synthesis_read(&vf->vd,samples);
    vf->pcm_offset+=samples;
    
    if(samples<target)
      if(_process_packet(vf,1)==0)
	vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
  }
  return 0;
}

/* seek to a playback time relative to the decompressed pcm stream 
   returns zero on success, nonzero on failure */
int ov_time_seek(OggVorbis_File *vf,double seconds){
  /* translate time to PCM position and call ov_pcm_seek */

  int link=-1;
  ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
  double time_total=ov_time_total(vf,-1);

  if(!vf->seekable)return(OV_ENOSEEK);
  if(seconds<0 || seconds>time_total)return(OV_EINVAL);
  
  /* which bitstream section does this time offset occur in? */
  for(link=vf->links-1;link>=0;link--){
    pcm_total-=vf->pcmlengths[link];
    time_total-=ov_time_total(vf,link);
    if(seconds>=time_total)break;
  }

  /* enough information to convert time offset to pcm offset */
  {
    ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate;
    return(ov_pcm_seek(vf,target));
  }
}

/* page-granularity version of ov_time_seek 
   returns zero on success, nonzero on failure */
int ov_time_seek_page(OggVorbis_File *vf,double seconds){
  /* translate time to PCM position and call ov_pcm_seek */

  int link=-1;
  ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
  double time_total=ov_time_total(vf,-1);

  if(!vf->seekable)return(OV_ENOSEEK);
  if(seconds<0 || seconds>time_total)return(OV_EINVAL);
  
  /* which bitstream section does this time offset occur in? */
  for(link=vf->links-1;link>=0;link--){
    pcm_total-=vf->pcmlengths[link];
    time_total-=ov_time_total(vf,link);
    if(seconds>=time_total)break;
  }

  /* enough information to convert time offset to pcm offset */
  {
    ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate;
    return(ov_pcm_seek_page(vf,target));
  }
}

/* tell the current stream offset cursor.  Note that seek followed by
   tell will likely not give the set offset due to caching */
ogg_int64_t ov_raw_tell(OggVorbis_File *vf){
  return(vf->offset);
}

/* return PCM offset (sample) of next PCM sample to be read */
ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){
  return(vf->pcm_offset);
}

/* return time offset (seconds) of next PCM sample to be read */
double ov_time_tell(OggVorbis_File *vf){
  /* translate time to PCM position and call ov_pcm_seek */

  int link=-1;
  ogg_int64_t pcm_total=0;
  double time_total=0.f;
  
  if(vf->seekable){
    pcm_total=ov_pcm_total(vf,-1);
    time_total=ov_time_total(vf,-1);
  
    /* which bitstream section does this time offset occur in? */
    for(link=vf->links-1;link>=0;link--){
      pcm_total-=vf->pcmlengths[link];
      time_total-=ov_time_total(vf,link);
      if(vf->pcm_offset>=pcm_total)break;
    }
  }

  return((double)time_total+(double)(vf->pcm_offset-pcm_total)/vf->vi[link].rate);
}

/*  link:   -1) return the vorbis_info struct for the bitstream section
                currently being decoded
           0-n) to request information for a specific bitstream section
    
    In the case of a non-seekable bitstream, any call returns the
    current bitstream.  NULL in the case that the machine is not
    initialized */

vorbis_info *ov_info(OggVorbis_File *vf,int link){
  if(vf->seekable){
    if(link<0)
      if(vf->decode_ready)
	return vf->vi+vf->current_link;
      else
	return NULL;
    else
      if(link>=vf->links)
	return NULL;
      else
	return vf->vi+link;
  }else{
    if(vf->decode_ready)
      return vf->vi;
    else
      return NULL;
  }
}

/* grr, strong typing, grr, no templates/inheritence, grr */
vorbis_comment *ov_comment(OggVorbis_File *vf,int link){
  if(vf->seekable){
    if(link<0)
      if(vf->decode_ready)
	return vf->vc+vf->current_link;
      else
	return NULL;
    else
      if(link>=vf->links)
	return NULL;
      else
	return vf->vc+link;
  }else{
    if(vf->decode_ready)
      return vf->vc;
    else
      return NULL;
  }
}

int host_is_big_endian() {
  ogg_int32_t pattern = 0xfeedface; /* deadbeef */
  unsigned char *bytewise = (unsigned char *)&pattern;
  if (bytewise[0] == 0xfe) return 1;
  return 0;
}

/* up to this point, everything could more or less hide the multiple
   logical bitstream nature of chaining from the toplevel application
   if the toplevel application didn't particularly care.  However, at
   the point that we actually read audio back, the multiple-section
   nature must surface: Multiple bitstream sections do not necessarily
   have to have the same number of channels or sampling rate.

   ov_read returns the sequential logical bitstream number currently
   being decoded along with the PCM data in order that the toplevel
   application can take action on channel/sample rate changes.  This
   number will be incremented even for streamed (non-seekable) streams
   (for seekable streams, it represents the actual logical bitstream
   index within the physical bitstream.  Note that the accessor
   functions above are aware of this dichotomy).

   input values: buffer) a buffer to hold packed PCM data for return
		 length) the byte length requested to be placed into buffer
		 bigendianp) should the data be packed LSB first (0) or
		             MSB first (1)
		 word) word size for output.  currently 1 (byte) or 
		       2 (16 bit short)

   return values: <0) error/hole in data (OV_HOLE)
                   0) EOF
		   n) number of bytes of PCM actually returned.  The
		   below works on a packet-by-packet basis, so the
		   return length is not related to the 'length' passed
		   in, just guaranteed to fit.

	    *section) set to the logical bitstream number */

long ov_read(OggVorbis_File *vf,char *buffer,int length,
		    int bigendianp,int word,int sgned,int *bitstream){
  int i,j;
  int host_endian = host_is_big_endian();

  while(1){
    if(vf->decode_ready){
      float **pcm;
      long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
      if(samples){
	/* yay! proceed to pack data into the byte buffer */

	long channels=ov_info(vf,-1)->channels;
	long bytespersample=word * channels;
	vorbis_fpu_control fpu;
	if(samples>length/bytespersample)samples=length/bytespersample;
	
	/* a tight loop to pack each size */
	{
	  int val;
	  if(word==1){
	    int off=(sgned?0:128);
	    vorbis_fpu_setround(&fpu);
	    for(j=0;j<samples;j++)
	      for(i=0;i<channels;i++){
		val=vorbis_ftoi(pcm[i][j]*128.f);
		if(val>127)val=127;
		else if(val<-128)val=-128;
		*buffer++=val+off;
	      }
	    vorbis_fpu_restore(fpu);
	  }else{
	    int off=(sgned?0:32768);

	    if(host_endian==bigendianp){
	      if(sgned){

		vorbis_fpu_setround(&fpu);
		for(i=0;i<channels;i++) { /* It's faster in this order */
		  float *src=pcm[i];
		  short *dest=((short *)buffer)+i;
		  for(j=0;j<samples;j++) {
		    val=vorbis_ftoi(src[j]*32768.f);
		    if(val>32767)val=32767;
		    else if(val<-32768)val=-32768;
		    *dest=val;
		    dest+=channels;
		  }
		}
		vorbis_fpu_restore(fpu);

	      }else{

		vorbis_fpu_setround(&fpu);
		for(i=0;i<channels;i++) {
		  float *src=pcm[i];
		  short *dest=((short *)buffer)+i;
		  for(j=0;j<samples;j++) {
		    val=vorbis_ftoi(src[j]*32768.f);
		    if(val>32767)val=32767;
		    else if(val<-32768)val=-32768;
		    *dest=val+off;
		    dest+=channels;
		  }
		}
		vorbis_fpu_restore(fpu);

	      }
	    }else if(bigendianp){

	      vorbis_fpu_setround(&fpu);
	      for(j=0;j<samples;j++)
		for(i=0;i<channels;i++){
		  val=vorbis_ftoi(pcm[i][j]*32768.f);
		  if(val>32767)val=32767;
		  else if(val<-32768)val=-32768;
		  val+=off;
		  *buffer++=(val>>8);
		  *buffer++=(val&0xff);
		}
	      vorbis_fpu_restore(fpu);

	    }else{
	      int val;
	      vorbis_fpu_setround(&fpu);
	      for(j=0;j<samples;j++)
	 	for(i=0;i<channels;i++){
		  val=vorbis_ftoi(pcm[i][j]*32768.f);
		  if(val>32767)val=32767;
		  else if(val<-32768)val=-32768;
		  val+=off;
		  *buffer++=(val&0xff);
		  *buffer++=(val>>8);
	  	}
	      vorbis_fpu_restore(fpu);  

	    }
	  }
	}
	
	vorbis_synthesis_read(&vf->vd,samples);
	vf->pcm_offset+=samples;
	if(bitstream)*bitstream=vf->current_link;
	return(samples*bytespersample);
      }
    }

    /* suck in another packet */
    switch(_process_packet(vf,1)){
    case 0:case OV_EOF:
      return(0);
    case OV_HOLE:
      return(OV_HOLE);
    case OV_EBADLINK:
      return(OV_EBADLINK);
    }
  }
}


/* end vorbisfile.c */


#define OGG_PATTERN "OggS"
#define OGG_STRING "OGG"

static char * 
GuessOggFile(char *buf, int len)
{
  if (len < (int) strlen(OGG_PATTERN)) return(QUE_STRING);
  if (strncasecmp(OGG_PATTERN, buf, strlen(OGG_PATTERN)) == 0) {
    return(OGG_STRING);
  }
  return(NULL);
}

char *
ExtOggFile(char *s)
{
  int l1 = strlen(".ogg");
  int l2 = strlen(s);

  if (strncasecmp(".ogg", &s[l2 - l1], l1) == 0) {
    return(OGG_STRING);
  }
  return(NULL);
}

static int started = 0;

#define READBUFSIZE 1024

static ogg_stream_state os; /* take physical pages, weld into a logical
	  		       stream of packets */
static ogg_page         og; /* one Ogg bitstream page. Vorbis packets are
			       inside */
static ogg_packet       op; /* one raw packet of data for decode */
  
static vorbis_info      vi; /* struct that stores all the static vorbis
			       bitstream settings */
static vorbis_comment   vc; /* struct that stores all the user comments */
  
static vorbis_dsp_state vd; /* central working state for the
			       packet->PCM decoder */
static vorbis_block     vb; /* local working space for packet->PCM decode */

#define SNACK_OGG_INT 19

static int
OpenOggFile(Sound *s, Tcl_Interp *interp, Tcl_Channel *ch, char *mode)
{
  if (s->debug > 2) Snack_WriteLog("    Enter OpenOggFile\n");

  if ((*ch = Tcl_OpenFileChannel(interp, s->fcname, mode, 420)) == 0) {
    return TCL_ERROR;
  }
  if (*ch == NULL) {
    Tcl_AppendResult(interp, "Ogg: unable to open file: ",
		     Snack_GetSoundFilename(s), NULL);
    return TCL_ERROR;
  } 
  Tcl_SetChannelOption(interp, *ch, "-translation", "binary");
#ifdef TCL_81_API
  Tcl_SetChannelOption(interp, *ch, "-encoding", "binary");
#endif
  
  if (s->extHead2 != NULL && s->extHead2Type != SNACK_OGG_INT) {
    Snack_FileFormat *ff;
    
    for (ff = Snack_GetFileFormats(); ff != NULL; ff = ff->nextPtr) {
      if (strcmp(s->fileType, ff->name) == 0) {
	if (ff->freeHeaderProc != NULL) {
	  (ff->freeHeaderProc)(s);
	}
      }
    }
  }
  
  if (s->extHead2 == NULL) {
    s->extHead2 = (char *) ckalloc(sizeof(OggVorbis_File));
    s->extHead2Type = SNACK_OGG_INT;
    ((OggVorbis_File *)s->extHead2)->nombitrate = 128000;
    ((OggVorbis_File *)s->extHead2)->maxbitrate = -1;
    ((OggVorbis_File *)s->extHead2)->minbitrate = -1;
    ((OggVorbis_File *)s->extHead2)->commList = NULL;
  }

  if (strcmp(mode,"r") == 0) {
    if(ov_open(interp, ch, (OggVorbis_File *)s->extHead2, NULL, 0) < 0) {
      Tcl_AppendResult(interp, "Input does not appear to be an Ogg bitstream",
		       NULL);
      return TCL_ERROR;
    }
  }

  if (s->debug > 2) Snack_WriteLog("    Exit OpenOggFile\n");
  
  return TCL_OK;
}

static int
CloseOggFile(Sound *s, Tcl_Interp *interp, Tcl_Channel *ch)
{
  if (s->debug > 2) Snack_WriteLog("    Enter CloseOggFile\n");

  if (started == 0) {
    ov_clear(interp, (OggVorbis_File *)s->extHead2);
    *ch = NULL;
  } else {

    /* Tell the library we're at end of stream */
    vorbis_analysis_wrote(&vd, 0);

    while (vorbis_analysis_blockout(&vd, &vb) == 1) {
      vorbis_analysis(&vb,&op);      
      ogg_stream_packetin(&os,&op);
      
      while (1) {
	int result = ogg_stream_pageout(&os, &og);
	if (result == 0) break;
	if (Tcl_Write(*ch, (char *) og.header, og.header_len) == -1)
	  return TCL_ERROR;
	if (Tcl_Write(*ch, (char *) og.body, og.body_len) == -1)
	  return TCL_ERROR;
	
	if (ogg_page_eos(&og)) break;
      }
    }

    /* clean up, vorbis_info_clear() must be called last */

    ogg_stream_clear(&os);
    vorbis_block_clear(&vb);
    vorbis_dsp_clear(&vd);
    vorbis_comment_clear(&vc);
    vorbis_info_clear(&vi);

    if (ch != NULL) {
      Tcl_Close(interp, *ch);
    }
    started = 0;
  }

  if (s->debug > 2) Snack_WriteLog("    Exit CloseOggFile\n");

  return TCL_OK;
}

float pcmout[READBUFSIZE];

static int
ReadOggSamples(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, char *ibuf,
		  float *obuf, int len)
{
  int nread = 0, bigendian = Snack_PlatformIsLittleEndian() ? 0 : 1;
  float *f  = obuf;
  int n, i, dummy;

  if (s->debug > 2) Snack_WriteLog("    Enter ReadOggSamples\n");

  while (nread < len) {
    int size = min(sizeof(pcmout), (len - nread) * s->sampsize);
    n = ov_read((OggVorbis_File *)s->extHead2, (char *)pcmout, size,
		bigendian, 2, 1, &dummy);
    if (n < 0) {
      return -1;
    } else if (n == 0) {
      return(nread);
    } else {
      short *r = (short *) pcmout;
      for (i = 0; i < n / s->sampsize; i++) {
	*f++ = (float) *r++;
      }
      nread += (n / s->sampsize);
    }
  }

  if (s->debug > 2) Snack_WriteLogInt("    Exit ReadOggSamples", nread);

  return(nread);
}

static int
SeekOggFile(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, int pos)
{
  if (pos == 0) return 0; /* ov_time_seek() does not like seeking to 0 */

  if (ov_pcm_seek((OggVorbis_File *)s->extHead2, (ogg_int64_t) pos)) {
    return(-1);
  } else {
    return(pos);
  }
}

static int
GetOggHeader(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, Tcl_Obj *obj,
	     char *buf)
{
  int i;
  vorbis_info *vi;
  vorbis_comment *vc;

  if (s->debug > 2) Snack_WriteLog("    Enter GetOggHeader\n"); 

  /* For the case when Tcl_Open has been done somewhere else */

  if (s->extHead2 != NULL && s->extHead2Type != SNACK_OGG_INT) {
    Snack_FileFormat *ff;
    
    for (ff = Snack_GetFileFormats(); ff != NULL; ff = ff->nextPtr) {
      if (strcmp(s->fileType, ff->name) == 0) {
	if (ff->freeHeaderProc != NULL) {
	  (ff->freeHeaderProc)(s);
	}
      }
    }
  }

  if (s->extHead2 == NULL) {
    s->extHead2 = (char *) ckalloc(sizeof(OggVorbis_File));
    s->extHead2Type = SNACK_OGG_INT;
    ((OggVorbis_File *)s->extHead2)->maxbitrate = -1;
    ((OggVorbis_File *)s->extHead2)->minbitrate = -1;

    if (ov_open(interp, &s->rwchan, (OggVorbis_File *)s->extHead2, 
		(char *)s->tmpbuf, s->firstNRead) < 0) {
      Tcl_AppendResult(interp, "Input does not appear to be an Ogg bitstream",
		       NULL);
      return TCL_ERROR;
    }
  }

  vi = ov_info((OggVorbis_File *)s->extHead2,-1);
    
  Snack_SetSampleRate(s, vi->rate);
  Snack_SetNumChannels(s, vi->channels);
  Snack_SetSampleEncoding(s, LIN16);
  Snack_SetBytesPerSample(s, 2);
  Snack_SetHeaderSize(s, 0);
  Snack_SetLength(s, (long)ov_pcm_total((OggVorbis_File *)s->extHead2, -1));
  ((OggVorbis_File *)s->extHead2)->nombitrate =
    ov_bitrate((OggVorbis_File *)s->extHead2, -1);
  vc = ov_comment((OggVorbis_File *)s->extHead2, -1);

  ((OggVorbis_File *)s->extHead2)->commList = Tcl_NewListObj(0, NULL);
  for (i = 0; i < vc->comments; i++) {
    Tcl_ListObjAppendElement(interp, ((OggVorbis_File *)s->extHead2)->commList,
			     Tcl_NewStringObj(vc->user_comments[i], -1));
  }

  if (s->debug > 2) Snack_WriteLog("    Exit GetOggHeader\n");

  return TCL_OK;
}

static int
PutOggHeader(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, Tcl_Obj *obj,
	     int objc, Tcl_Obj *CONST objv[], int len)
{
  int arg, n = 0;
  OggVorbis_File *of = (OggVorbis_File *)s->extHead2;
  Tcl_Obj **listObj;
  static char *subOptionStrings[] = {
    "-comment", "-maxbitrate", "-minbitrate", "-nominalbitrate", NULL
  };
  enum subOptions {
    COMMENT, MAX, MIN, NOMINAL
  };

  if (s->debug > 2) Snack_WriteLog("    Enter PutOggHeader\n"); 

  for (arg = 0; arg < objc; arg+=2) {
    int index;

    if (Tcl_GetIndexFromObj(interp, objv[arg], subOptionStrings,
			    "option", 0, &index) != TCL_OK) {
      return TCL_ERROR;
    }

    if (arg + 1 == objc) {
      Tcl_AppendResult(interp, "No argument given for ",
		       subOptionStrings[index], " option", (char *) NULL);
      return TCL_ERROR;
    }
    
    switch ((enum subOptions) index) {
    case COMMENT:
      {
	if (Tcl_ListObjGetElements(interp, objv[arg+1], &n, &listObj) !=
	    TCL_OK) {
	  return TCL_ERROR;
	}
	break;
      }
    case MAX:
      {
	if (Tcl_GetIntFromObj(interp, objv[arg+1], &of->maxbitrate) != TCL_OK)
	  return TCL_ERROR;
	break;
      }
    case MIN:
      {
	if (Tcl_GetIntFromObj(interp, objv[arg+1], &of->minbitrate) != TCL_OK)
	  return TCL_ERROR;
	break;
      }
    case NOMINAL:
      {
	if (Tcl_GetIntFromObj(interp, objv[arg+1], &of->nombitrate) != TCL_OK)
	  return TCL_ERROR;
	break;
      }
    }
  }

  /* For the case when Tcl_Open has been done somewhere else */

  if (started == 0) {
    ogg_packet header;
    ogg_packet header_comm;
    ogg_packet header_code;

    if (s->extHead2 != NULL && s->extHead2Type != SNACK_OGG_INT) {
      Snack_FileFormat *ff;
      
      for (ff = Snack_GetFileFormats(); ff != NULL; ff = ff->nextPtr) {
	if (strcmp(s->fileType, ff->name) == 0) {
	  if (ff->freeHeaderProc != NULL) {
	    (ff->freeHeaderProc)(s);
	  }
	}
      }
    }

    if (s->extHead2 == NULL) {
      s->extHead2 = (char *) ckalloc(sizeof(OggVorbis_File));
      s->extHead2Type = SNACK_OGG_INT;
      ((OggVorbis_File *)s->extHead2)->nombitrate = 128000;
      ((OggVorbis_File *)s->extHead2)->maxbitrate = -1;
      ((OggVorbis_File *)s->extHead2)->minbitrate = -1;
      ((OggVorbis_File *)s->extHead2)->commList = NULL;
      of = (OggVorbis_File *)s->extHead2;
    }

    started = 1;
    vorbis_info_init(&vi);
    vorbis_encode_init(&vi, s->nchannels, s->samprate, of->maxbitrate,
		       of->nombitrate, of->minbitrate);

    if (of->commList != NULL && n == 0) {
      Tcl_ListObjGetElements(interp, of->commList, &n, &listObj);
    }

    if (n > 0) {
      int i;
      
      vorbis_comment_init(&vc);      
      for (i = 0; i < n; i++) {
	vorbis_comment_add(&vc, Tcl_GetStringFromObj(listObj[i], NULL));
      }
    }

    vorbis_analysis_init(&vd, &vi);
    vorbis_block_init(&vd, &vb);

    srand(time(NULL));
    ogg_stream_init(&os, rand());
    
    vorbis_analysis_headerout(&vd, &vc, &header, &header_comm, &header_code);
    ogg_stream_packetin(&os, &header);				 
    ogg_stream_packetin(&os, &header_comm);
    ogg_stream_packetin(&os, &header_code);
    
    
    if (ogg_stream_flush(&os, &og) != 0) {
      if (Tcl_Write(ch, (char *) og.header, og.header_len) == -1)
	return TCL_ERROR;
      if (Tcl_Write(ch, (char *) og.body, og.body_len) == -1)
	return TCL_ERROR;
    }
  }
  s->headSize = 0;
  
  if (s->debug > 2) Snack_WriteLog("    Exit PutOggHeader\n"); 

  return TCL_OK;
}

static int
WriteOggSamples(Sound *s, Tcl_Channel ch, Tcl_Obj *obj, int start, int length)
{
  int eos = 0, pos = start, end = start + length;
  long i, j, k;

  if (s->debug > 2) Snack_WriteLogInt("    Enter WriteOggSamples", length);
  
  while (pos < end) {
    float **buffer = vorbis_analysis_buffer(&vd, READBUFSIZE);
    
    /* uninterleave samples */
    Snack_GetSoundData(s, pos, pcmout, READBUFSIZE);
    for (i = 0, k = 0; i < READBUFSIZE / s->nchannels; i++) {
      for (j = 0; j < s->nchannels; j++, k++) {	
	if (s->readStatus == READ) {
	  buffer[j][i] = FSAMPLE(s, pos) / 32768.0f;
	} else {
	  buffer[j][i] = pcmout[k] / 32768.0f;
	}
	pos++;
	if (pos > end && j == s->nchannels-1) break;
      }
      if (pos > end && j == s->nchannels-1) break;
    }
    
    /* tell the library how much we actually submitted */
    vorbis_analysis_wrote(&vd, i);
  }
  
  while(vorbis_analysis_blockout(&vd, &vb)==1){
    vorbis_analysis(&vb,&op);
    ogg_stream_packetin(&os,&op);
    
    while(!eos){
      int result = ogg_stream_pageout(&os, &og);
      if (result == 0) break;
      if (Tcl_Write(ch, (char *) og.header, og.header_len) == -1)
	return TCL_ERROR;
      if (Tcl_Write(ch, (char *) og.body, og.body_len) == -1)
	return TCL_ERROR;
      
      if (ogg_page_eos(&og)) eos=1;
    }
  }

  if (s->debug > 2) Snack_WriteLog("    Exit WriteOggSamples\n");

  return(length);
}

void
FreeOggHeader(Sound *s)
{
  if (s->debug > 2) Snack_WriteLog("    Enter FreeOggHeader\n");

  if (s->extHead2 != NULL) {
    /* To be cleared commList */
    ckfree((char *)s->extHead2);
    s->extHead2 = NULL;
    s->extHead2Type = 0;
  }

  if (s->debug > 2) Snack_WriteLog("    Exit FreeOggHeader\n");
}

int
ConfigOgg(Sound *s, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
  int arg, index;
  OggVorbis_File *of = (OggVorbis_File *)s->extHead2;
  static char *optionStrings[] = {
    "-comment", "-maxbitrate", "-minbitrate", "-nominalbitrate", NULL
  };
  enum options {
    COMMENT, MAX, MIN, NOMINAL
  };
  
  if (s->debug > 2) Snack_WriteLog("    Enter ConfigOgg\n");
  
  if (s->extHead2 != NULL && s->extHeadType != SNACK_OGG_INT) {
    Snack_FileFormat *ff;
    
    for (ff = Snack_GetFileFormats(); ff != NULL; ff = ff->nextPtr) {
      if (strcmp(s->fileType, ff->name) == 0) {
	if (ff->freeHeaderProc != NULL) {
	  (ff->freeHeaderProc)(s);
	}
      }
    }
  }
  
  if (s->extHead2 == NULL) {
    s->extHead2 = (char *) ckalloc(sizeof(OggVorbis_File));
    s->extHeadType = SNACK_OGG_INT;
    ((OggVorbis_File *)s->extHead2)->nombitrate = 128000;
    ((OggVorbis_File *)s->extHead2)->maxbitrate = -1;
    ((OggVorbis_File *)s->extHead2)->minbitrate = -1;
    ((OggVorbis_File *)s->extHead2)->commList = NULL;
    of = (OggVorbis_File *)s->extHead2;
  }
  
  if (objc < 3) return 0;


  if (objc == 3) { /* get option */
    if (Tcl_GetIndexFromObj(interp, objv[2], optionStrings, "option", 0,
			    &index) != TCL_OK) {
      Tcl_AppendResult(interp, ", or\n", NULL);
      return 0;
    }

    switch ((enum options) index) {
    case COMMENT:
      {
	Tcl_SetObjResult(interp, of->commList);
	break;
      }
    case MAX:
      {
	Tcl_SetObjResult(interp, Tcl_NewIntObj(of->maxbitrate));
	break;
      }
    case MIN:
      {
	Tcl_SetObjResult(interp, Tcl_NewIntObj(of->minbitrate));
	break;
      }
    case NOMINAL:
      {
	Tcl_SetObjResult(interp, Tcl_NewIntObj(of->nombitrate));
	break;
      }
    }
  } else {
    for (arg = 2; arg < objc; arg+=2) {
      int index;
      
      if (Tcl_GetIndexFromObj(interp, objv[arg], optionStrings, "option", 0,
			      &index) != TCL_OK) {
	return TCL_ERROR;
      }
      
      if (arg + 1 == objc) {
	Tcl_AppendResult(interp, "No argument given for ",
			 optionStrings[index], " option\n", (char *) NULL);
	return 0;
      }
      
      switch ((enum options) index) {
      case COMMENT:
	{
	  int i, n;
	  Tcl_Obj **listObj;
	  
	  if (Tcl_ListObjGetElements(interp, objv[arg+1], &n, &listObj) !=
	      TCL_OK) {
	    return TCL_ERROR;
	  }
	  /* To be cleared commList */
	  of->commList = Tcl_NewListObj(0, NULL);
	  for (i = 0; i < n; i++) {
	    Tcl_ListObjAppendElement(interp, of->commList, listObj[i]);
	  }
	  break;
	}
      case MAX:
	{
	  if (Tcl_GetIntFromObj(interp,objv[arg+1], &of->maxbitrate) != TCL_OK)
	    return TCL_ERROR;
	  break;
	}
      case MIN:
	{
	  if (Tcl_GetIntFromObj(interp,objv[arg+1], &of->minbitrate) != TCL_OK)
	    return TCL_ERROR;
	  break;
	}
      case NOMINAL:
	{
	  if (Tcl_GetIntFromObj(interp,objv[arg+1], &of->nombitrate) != TCL_OK)
	    return TCL_ERROR;
	  break;
	}
      }
    }
  }

  if (s->debug > 2) Snack_WriteLog("    Exit ConfigOgg\n");

  return 1;
}

#define OGGFILE_VERSION "1.2"

Snack_FileFormat snackOggFormat = {
  OGG_STRING,
  GuessOggFile,
  GetOggHeader,
  ExtOggFile,
  PutOggHeader,
  OpenOggFile,
  CloseOggFile,
  ReadOggSamples,
  WriteOggSamples,
  SeekOggFile,
  FreeOggHeader,
  ConfigOgg,
  (Snack_FileFormat *) NULL
};

/* Called by "load libsnackogg" */
EXPORT(int, Snackogg_Init) _ANSI_ARGS_((Tcl_Interp *interp))
{
  int res;
  
#ifdef USE_TCL_STUBS
  if (Tcl_InitStubs(interp, "8", 0) == NULL) {
    return TCL_ERROR;
  }
#endif
  
#ifdef USE_SNACK_STUBS
  if (Snack_InitStubs(interp, "2", 0) == NULL) {
    return TCL_ERROR;
  }
#endif
  
  res = Tcl_PkgProvide(interp, "snackogg", OGGFILE_VERSION);
  
  if (res != TCL_OK) return res;

  Tcl_SetVar(interp, "snack::snackogg", OGGFILE_VERSION, TCL_GLOBAL_ONLY);

  Snack_CreateFileFormat(&snackOggFormat);

  return TCL_OK;
}

EXPORT(int, Snackogg_SafeInit)(Tcl_Interp *interp)
{
  return Snackogg_Init(interp);
}

Changes to snack/generic/SphereFile.c.

25
26
27
28
29
30
31

32
33
34
35
36
37
38
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39







+







   if (ch) sp_close((SP_FILE *)ch); \
   return TCL_ERROR; \
}

#define NIST_STRING "NIST"
#define SPHERE_STRING "SPHERE"
#define SPHERE_HEADERSIZE 1024
#define SNACK_SPHERE_INT 17

static int
GetSphereHeader(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, Tcl_Obj *obj,
	      char *buf);

static char * 
GuessSphereFile(char *buf, int len)
70
71
72
73
74
75
76












77
78

79
80
81
82
83
84
85
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







+
+
+
+
+
+
+
+
+
+
+
+


+







  }
  /*
    Hack for the pculaw format. Read header again because
    sp_set_data_mode() has to be called.
    */
  GetSphereHeader(s, interp, *ch, NULL, NULL);

  if (s->extHead != NULL && s->extHeadType != SNACK_SPHERE_INT) {
    Snack_FileFormat *ff;
    
    for (ff = Snack_GetFileFormats(); ff != NULL; ff = ff->nextPtr) {
      if (strcmp(s->fileType, ff->name) == 0) {
	if (ff->freeHeaderProc != NULL) {
	  (ff->freeHeaderProc)(s);
	}
      }
    }
  }
  
  if (s->extHead == NULL) {
    s->extHead = ckalloc(sizeof(short) * SPHERE_BUFFER_SIZE);
    s->extHeadType = SNACK_SPHERE_INT;
  }

  return TCL_OK;
}

static int
CloseSphereFile(Sound *s, Tcl_Interp *interp, Tcl_Channel *ch)
103
104
105
106
107
108
109
110

111
112
113
114
115
116
117
117
118
119
120
121
122
123

124
125
126
127
128
129
130
131







-
+







  short *r  = (short *) s->extHead;
  int   *is = (int *)   s->extHead;
  float *fs = (float *) s->extHead;
  float *f  = obuf;
  int size = min(tot, SPHERE_BUFFER_SIZE / Snack_GetNumChannels(s));
  int read = sp_read_data(s->extHead, size, (SP_FILE *)ch);

  if (sp_error((SP_FILE *)ch)) {
  if (!(sp_error((SP_FILE *)ch) == 0 || sp_error((SP_FILE *)ch) == 101)) {
    return -1;
  }
  
  for (i = 0; i < read * Snack_GetNumChannels(s); i++) {
    switch (s->encoding) {
    case LIN16:
      if (s->swap) *r = Snack_SwapShort(*r);
262
263
264
265
266
267
268
269

270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286

287
288
289
290

291
292
293
294
295
296
297
298
299
300
301
302
303

304
305
306
307
308
309
310
276
277
278
279
280
281
282

283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304

305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326







-
+

















+



-
+













+







      if (Snack_GetBytesPerSample(s) == 2) {
         Snack_SetSampleEncoding(s, LIN16);
      } else {
         Snack_SetSampleEncoding(s, LIN8);
      }
   }
   if (sample_coding != "") {
      free(sample_coding);
     free(sample_coding);
   }

   /* header size shouldn't be needed by user,
      so it is not given directly by SPHERE user interface */

   Snack_SetHeaderSize(s, SPHERE_HEADERSIZE);
   Snack_SetLength(s, sample_cnt);

   return TCL_OK;
}

void
FreeSphereHeader(Sound *s)
{
  if (s->extHead != NULL) {
    ckfree((char *) s->extHead);
    s->extHead = NULL;
    s->extHeadType = 0;
  }
}

#define SPHEREFILE_VERSION "1.1"
#define SPHEREFILE_VERSION "1.2"

Snack_FileFormat snackSphFormat = {
  SPHERE_STRING,
  GuessSphereFile,
  GetSphereHeader,
  ExtSphereFile,
  NULL,
  OpenSphereFile,
  CloseSphereFile,
  ReadSphereSamples,
  NULL,
  SeekSphereFile,
  FreeSphereHeader,
  NULL,
  (Snack_FileFormat *) NULL
};

/* Called by "load libsnacksphere" */
EXPORT(int, Snacksphere_Init) _ANSI_ARGS_((Tcl_Interp *interp))
{
  int res;

Changes to snack/generic/ffa.c.

63
64
65
66
67
68
69
70

71
72
73
74
75
76
77
63
64
65
66
67
68
69

70
71
72
73
74
75
76
77







-
+







static int sint_init = 0;
static int n2pow,nthpo;
static double theta, wpr, wpi;

#define  SNACK_PI2  6.283185307179586
#define  P7   0.707106781186548
#define  LN2  0.6931471805599453
#define  DB   4.34294481903251830000000
#define  DB   4.34294481903251830000000 /*  = 10 / ln(10)  */
#define  WMIN 1.0
#define  CORRN (float) 138.308998699
#define  CORR0 (float) 132.288396199

int
Snack_InitFFT(int n)
{

Changes to snack/generic/jkAudIO.h.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
195
196
197
198
199
200
201

202
203
204
205
206
207
208
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209







+







extern int  SnackAudioReadable(ADesc *A);
extern int  SnackAudioPlayed(ADesc *A);
extern int  SnackAudioWriteable(ADesc *A);

extern int SnackAudioGetEncodings(char *device);
extern void SnackAudioGetRates(char *device, char *buf, int n);
extern int SnackAudioMaxNumberChannels(char *device);
extern int SnackAudioMinNumberChannels(char *device);

extern void ASetRecGain(int gain);
extern void ASetPlayGain(int gain);
extern int  AGetRecGain();
extern int  AGetPlayGain();

extern void SnackMixerGetInputJackLabels(char *buf, int n);

Changes to snack/generic/jkAudio.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or

Changes to snack/generic/jkCanvItems.h.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
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
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







-
+
+
+













-
+
+
+
+








#define CONF_WIDTH 1
#define CONF_PPS 2
#define CONF_WIDTH_PPS 3

extern int  CheckFFTlen(Tcl_Interp *interp, int fftlen);

extern int  CheckWinlen(Tcl_Interp *interp, int winlen);
extern int  CheckWinlen(Tcl_Interp *interp, int winlen, int fftlen);

extern int  CheckLPCorder(Tcl_Interp *interp, int lpcorder);

#if !defined(WIN) && !defined(MAC)
#define TkPutImage(colors, ncolors, display, pixels, gc, image, \
		   destx, desty, srcx, srcy, width, height) \
        XPutImage(                  display, pixels, gc, image, \
		   destx, desty, srcx, srcy, width, height);
#endif

#if defined WIN || defined MAC
#  define XFree(data) {if ((data) != NULL) ckfree((char *) (data));}
#endif

#if defined MAC
#include <tclMacMath.h>
#  include <tclMacMath.h>
#  define hypot hypotd

  extern double hypot(double x, double y);
#endif

#define OptSpecified(option) (configSpecs[option].specFlags & TK_CONFIG_OPTION_SPECIFIED)

#ifdef __cplusplus
}
#endif

Changes to snack/generic/jkCanvSect.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
28
29
30
31
32
33
34


35
36
37
38
39
40
41
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43







+
+







#include "tk.h"
#include "jkSound.h"
#include "jkCanvItems.h"
#include <string.h>

#define SNACK_DEFAULT_SECTWINTYPE      SNACK_WIN_HAMMING
#define SNACK_DEFAULT_SECTWINTYPE_NAME "hamming"

#define SNACK_DEFAULT_LPC_ORDER        "20"

/*
 * Section item structure
 */

typedef struct SectionItem  {

65
66
67
68
69
70
71



72
73
74
75
76
77
78
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83







+
+
+







  XPoint fpts[5];
  char *channelstr;
  int debug;
  double topFrequency;
  double maxValue;
  double minValue;
  char *windowTypeStr;
  char *analysisTypeStr;
  int type;
  int lpcOrder;
  Tcl_Interp *interp;
  double preemph;

} SectionItem;

Tk_CustomOption sectTagsOption = { (Tk_OptionParseProc *) NULL,
				   (Tk_OptionPrintProc *) NULL,
93
94
95
96
97
98
99
100



101
102
103
104
105
106
107
98
99
100
101
102
103
104

105
106
107
108
109
110
111
112
113
114







-
+
+
+







  OPTION_STIPPLE,
  OPTION_FRAME,
  OPTION_TOPFREQUENCY,
  OPTION_CHANNEL,
  OPTION_MAXVAL,
  OPTION_MINVAL,
  OPTION_SKIP,
  OPTION_WINTYPE
  OPTION_WINTYPE,
  OPTION_ANALYSISTYPE,
  OPTION_LPCORDER
} ConfigSpec;

static Tk_ConfigSpec configSpecs[] = {

  {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL,
   "nw", Tk_Offset(SectionItem, anchor), TK_CONFIG_DONT_SET_DEFAULT},

154
155
156
157
158
159
160






161
162
163
164
165
166
167
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180







+
+
+
+
+
+







   "-80.0", Tk_Offset(SectionItem, minValue), 0},

  {TK_CONFIG_INT, "-skip", (char *) NULL, (char *) NULL,
   "-1", Tk_Offset(SectionItem, si.skip), 0},

  {TK_CONFIG_STRING, "-windowtype", (char *) NULL, (char *) NULL,
   SNACK_DEFAULT_SECTWINTYPE_NAME, Tk_Offset(SectionItem, windowTypeStr), 0},

  {TK_CONFIG_STRING, "-analysistype", (char *) NULL, (char *) NULL,
   "fft", Tk_Offset(SectionItem, analysisTypeStr), 0},

  {TK_CONFIG_INT, "-lpcorder", (char *) NULL, (char *) NULL,
   SNACK_DEFAULT_LPC_ORDER, Tk_Offset(SectionItem, lpcOrder), 0},

  {TK_CONFIG_INT, "-debug", (char *) NULL, (char *) NULL,
   "0", Tk_Offset(SectionItem, debug), 0},

  {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
   (char *) NULL, 0, 0}

259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
272
273
274
275
276
277
278


279
280
281
282
283
284
285







-
-







  sectPtr->soundName = NULL;
  sectPtr->sound = NULL;
  sectPtr->si.samprate = 16000;
  sectPtr->si.BufPos = 0;
  sectPtr->si.fftlen = 512;
  sectPtr->si.winlen = 256;
  sectPtr->preemph = 0.0;
  sectPtr->si.fftmax = -10000;
  sectPtr->si.fftmin = 10000;
  sectPtr->si.hamwin = (float *) ckalloc(NMAX * sizeof(float));
  sectPtr->si.abmax = 0.0f;
  sectPtr->xfft = (float *)  ckalloc(NMAX * sizeof(float));
  sectPtr->ffts = (double *) ckalloc(NMAX / 2 * sizeof(double));
  sectPtr->height = 256;
  sectPtr->width = 256;
  sectPtr->startSmp = 0;
288
289
290
291
292
293
294



295
296
297
298
299
300
301
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315







+
+
+







  sectPtr->maxValue = 0.0;
  sectPtr->minValue = -80.0;
  sectPtr->si.validStart = 0;
  sectPtr->si.skip = -1;
  sectPtr->si.windowType = SNACK_DEFAULT_SECTWINTYPE;
  sectPtr->si.windowTypeSet = SNACK_DEFAULT_SECTWINTYPE;
  sectPtr->windowTypeStr = NULL;
  sectPtr->analysisTypeStr = NULL;
  sectPtr->type = 0;
  sectPtr->lpcOrder = atoi(SNACK_DEFAULT_LPC_ORDER);
  sectPtr->interp = interp;

  if (sectPtr->si.hamwin == NULL) {
    Tcl_AppendResult(interp, "Couldn't allocate analysis window buffer!",NULL);
    return TCL_ERROR;
  }

382
383
384
385
386
387
388






























































389
390
391
392
393
394
395
396

397
398
399
400
401
402




403

404
405
406
407
408
409


410
411
412
413
414
415
416
417


418
419
420
421
422
423
424



































425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496








































































497
498
499
500


501
502
503
504
505
506
507
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477

478
479
480
481
482

483
484
485
486
487
488

489
490
491
492
493
494
495
496
497

498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541








































































542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613




614
615
616
617
618
619
620
621
622







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+








+




-

+
+
+
+
-
+





-
+
+







-
+
+







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+








  ComputeSectionBbox(sectPtr->canvas, sectPtr);

  if (sectPtr->debug) Snack_WriteLog("Exit ComputeSectionCoords\n"); 

  return TCL_OK;
}

void
GetFloatMonoSigSect(SnackItemInfo *siPtr,SnackLinkedFileInfo *info,
		    float *sig,int beg, int len) {
  /* sig buffer must be allocated, file must be open! */

  int i;

  if (siPtr->storeType == SOUND_IN_MEMORY) {
    if (siPtr->nchannels == 1 || siPtr->channel != -1) {
      int p = beg * siPtr->nchannels + siPtr->channel;

      for (i = 0; i < len; i++) {
	sig[i] = (float) (FSAMPLE(siPtr, p));
	p += siPtr->nchannels;
      }
    } else {
      int c;

      for (i = 0; i < len; i++) {
	sig[i] = 0.0;
      }
      for (c = 0; c < siPtr->nchannels; c++) {
	int p = beg * siPtr->nchannels + c;

	for (i = 0; i < len; i++) {
	  sig[i] += (float) (FSAMPLE(siPtr, p));
	  p += siPtr->nchannels;
	}
      }
      for (i = 0; i < len; i++) {
	sig[i] /= siPtr->nchannels;
      }
    }
  } else { /* storeType != SOUND_IN_MEMORY */
    if (siPtr->nchannels == 1 || siPtr->channel != -1) {
      int p = beg * siPtr->nchannels + siPtr->channel;
	
      for (i = 0; i < len; i++) {
	sig[i] = (float) (GetSample(info, p));
	p += siPtr->nchannels;
      }
    } else {
      int c;
	
      for (i = 0; i < len; i++) {
	sig[i] = 0.0;
      }
      for (c = 0; c < siPtr->nchannels; c++) {
	int p = beg * siPtr->nchannels + c;
	  
	for (i = 0; i < len; i++) {
	  sig[i] += (float) (GetSample(info, p));
	  p += siPtr->nchannels;
	}
      }
      for (i = 0; i < len; i++) {
	sig[i] /= siPtr->nchannels;
      }
    }
  }
}

void
ComputeSection(Tk_Item *itemPtr)
{
  SectionItem *sectPtr = (SectionItem *) itemPtr;
  SnackItemInfo *siPtr = &sectPtr->si;
  int i, j;
  int fftlen     = siPtr->fftlen;
  int winlen     = siPtr->winlen;
  float preemph  = siPtr->preemph;
  int RestartPos = siPtr->RestartPos - siPtr->validStart;
  int storeType  = siPtr->storeType;
  int n, skip = siPtr->skip;
  double Max = -1000.0, Min = 1000.0;
  SnackLinkedFileInfo info;
  float *sig_lpc;
  float presample = 0.0;
  int siglen;
  float g_lpc;

  
  if (sectPtr->debug) Snack_WriteLogInt("Enter ComputeSection", sectPtr->ssmp);

  if (skip < 1) {
    skip = fftlen;
  }
  n = (sectPtr->esmp - siPtr->RestartPos) / skip;
  siglen = sectPtr->esmp - siPtr->RestartPos;
  n = siglen / skip;

  for (i = 0; i < fftlen/2; i++) {
    sectPtr->ffts[i] = 0.0;
  }

  if (n == 0) return;

  Snack_InitFFT(siPtr->fftlen);
  Snack_InitFFT(fftlen);
  Snack_InitWindow(siPtr->hamwin, winlen, fftlen, siPtr->windowType);

  if (storeType != SOUND_IN_MEMORY) {
    if (OpenLinkedFile(sectPtr->sound, &info) != TCL_OK) {
      return;
    }
  }

  if (sectPtr->type != 0 && n > 0) { /* LPC + FFT */

    sig_lpc = (float *) ckalloc(siglen * sizeof(float));

    GetFloatMonoSigSect(siPtr,&info,sig_lpc,RestartPos,siglen);
    if (RestartPos > 0)
	GetFloatMonoSigSect(siPtr,&info,&presample,RestartPos-1,1);
    PreEmphase(sig_lpc,presample,siglen,preemph);

    /* windowing signal to make lpc look more like the fft spectrum ??? */
    for (i = 0; i < winlen/2; i++) {
      sig_lpc[i] = sig_lpc[i] * siPtr->hamwin[i];
    }
    for (i = winlen/2; i < winlen; i++) {
      sig_lpc[i+siglen-winlen] = sig_lpc[i+siglen-winlen] * siPtr->hamwin[i];
    }

    g_lpc = LpcAnalysis(sig_lpc,siglen,sectPtr->xfft,sectPtr->lpcOrder);
    ckfree((char *)sig_lpc);

    for (i=0; i<=sectPtr->lpcOrder; i++) {
      /* the factor is a guess, try looking for analytical value */
      sectPtr->xfft[i] = sectPtr->xfft[i] * 5000000000.0f;
    }
    for (i = sectPtr->lpcOrder + 1; i < fftlen; i++) {
      sectPtr->xfft[i] = 0.0;
    }
    
    Snack_DBPowerSpectrum(sectPtr->xfft);
    
    for (i = 0; i < fftlen/2; i++) {
      sectPtr->ffts[i] = -sectPtr->xfft[i];
    }
  } else {  /* usual FFT */
    
  for (j = 0; j < n; j++) {
    if (storeType == SOUND_IN_MEMORY) {
      if (siPtr->nchannels == 1 || siPtr->channel != -1) {
	int p = (RestartPos + j * skip) * siPtr->nchannels + siPtr->channel;

	for (i = 0; i < fftlen; i++) {
	  sectPtr->xfft[i] = (float) ((FSAMPLE(siPtr, p + siPtr->nchannels)
				       - preemph * FSAMPLE(siPtr, p))
				      * siPtr->hamwin[i]);
	  p += siPtr->nchannels;
	}
      } else {
	int c;
	
	for (i = 0; i < fftlen; i++) {
	  sectPtr->xfft[i] = 0.0;
	}
	for (c = 0; c < siPtr->nchannels; c++) {
	  int p = (RestartPos + j * skip) * siPtr->nchannels + c;
	  
	  for (i = 0; i < fftlen; i++) {
	    sectPtr->xfft[i] += (float) ((FSAMPLE(siPtr, p + siPtr->nchannels)
					  - preemph * FSAMPLE(siPtr, p))
					 * siPtr->hamwin[i]);
	    p += siPtr->nchannels;
	  }
	}
	for (i = 0; i < fftlen; i++) {
	  sectPtr->xfft[i] /= siPtr->nchannels;
	}
      }
    } else { /* storeType != SOUND_IN_MEMORY */
      if (siPtr->nchannels == 1 || siPtr->channel != -1) {
	int p = (RestartPos + j * skip) * siPtr->nchannels + siPtr->channel;
	
	for (i = 0; i < fftlen; i++) {
	  sectPtr->xfft[i] = (float) ((GetSample(&info, p + siPtr->nchannels)
				       - preemph * GetSample(&info, p))
				      * siPtr->hamwin[i]);
	  p += siPtr->nchannels;
	}
      } else {
	int c;
	
	for (i = 0; i < fftlen; i++) {
	  sectPtr->xfft[i] = 0.0;
	}
	for (c = 0; c < siPtr->nchannels; c++) {
	  int p = (RestartPos + j * skip) * siPtr->nchannels + c;
	  
	  for (i = 0; i < fftlen; i++) {
	    sectPtr->xfft[i] += (float) ((GetSample(&info, p +siPtr->nchannels)
					  - preemph * GetSample(&info, p))
					 * siPtr->hamwin[i]);
	    p += siPtr->nchannels;
	  }
	}
	for (i = 0; i < fftlen; i++) {
	  sectPtr->xfft[i] /= siPtr->nchannels;
	}
      }
    }

    Snack_DBPowerSpectrum(sectPtr->xfft);

    for (i = 0; i < fftlen/2; i++) {
      sectPtr->ffts[i] += sectPtr->xfft[i];
    }
  }

  for (i = 0; i < fftlen/2; i++) {
    sectPtr->ffts[i] = sectPtr->ffts[i] / (float) n;
    for (j = 0; j < n; j++) {
      if (storeType == SOUND_IN_MEMORY) {
	if (siPtr->nchannels == 1 || siPtr->channel != -1) {
	  int p = (RestartPos + j * skip) * siPtr->nchannels + siPtr->channel;
	  
	  for (i = 0; i < fftlen; i++) {
	    sectPtr->xfft[i] = (float) ((FSAMPLE(siPtr, p + siPtr->nchannels)
					 - preemph * FSAMPLE(siPtr, p))
					* siPtr->hamwin[i]);
	    p += siPtr->nchannels;
	  }
	} else {
	  int c;
	  
	  for (i = 0; i < fftlen; i++) {
	    sectPtr->xfft[i] = 0.0;
	  }
	  for (c = 0; c < siPtr->nchannels; c++) {
	    int p = (RestartPos + j * skip) * siPtr->nchannels + c;
	    
	    for (i = 0; i < fftlen; i++) {
	      sectPtr->xfft[i] += (float)((FSAMPLE(siPtr, p + siPtr->nchannels)
					   - preemph * FSAMPLE(siPtr, p))
					  * siPtr->hamwin[i]);
	      p += siPtr->nchannels;
	    }
	  }
	  for (i = 0; i < fftlen; i++) {
	    sectPtr->xfft[i] /= siPtr->nchannels;
	  }
	}
      } else { /* storeType != SOUND_IN_MEMORY */
	if (siPtr->nchannels == 1 || siPtr->channel != -1) {
	  int p = (RestartPos + j * skip) * siPtr->nchannels + siPtr->channel;
	  
	  for (i = 0; i < fftlen; i++) {
	    sectPtr->xfft[i] = (float) ((GetSample(&info, p + siPtr->nchannels)
					 - preemph * GetSample(&info, p))
					* siPtr->hamwin[i]);
	    p += siPtr->nchannels;
	  }
	} else {
	  int c;
	  
	  for (i = 0; i < fftlen; i++) {
	    sectPtr->xfft[i] = 0.0;
	  }
	  for (c = 0; c < siPtr->nchannels; c++) {
	    int p = (RestartPos + j * skip) * siPtr->nchannels + c;
	    
	    for (i = 0; i < fftlen; i++) {
	      sectPtr->xfft[i] += (float)((GetSample(&info, p+siPtr->nchannels)
					   - preemph * GetSample(&info, p))
					  * siPtr->hamwin[i]);
	      p += siPtr->nchannels;
	    }
	  }
	  for (i = 0; i < fftlen; i++) {
	    sectPtr->xfft[i] /= siPtr->nchannels;
	  }
	}
      }
      
      Snack_DBPowerSpectrum(sectPtr->xfft);
      
      for (i = 0; i < fftlen/2; i++) {
	sectPtr->ffts[i] += sectPtr->xfft[i];
      }
    }
    
    for (i = 0; i < fftlen/2; i++) {
      sectPtr->ffts[i] = sectPtr->ffts[i] / (float) n;
    if (sectPtr->ffts[i] > Max) Max = sectPtr->ffts[i];
    if (sectPtr->ffts[i] < Min) Min = sectPtr->ffts[i];
  }  

    }
  }
  if (storeType != SOUND_IN_MEMORY) {
    CloseLinkedFile(&info);
  }

  if (sectPtr->debug) Snack_WriteLog("Exit ComputeSection"); 
}

586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
701
702
703
704
705
706
707




708
709
710
711
712
713
714







-
-
-
-







  sectPtr->si.channel = sectPtr->si.channelSet;
  if (sectPtr->si.nchannels == 1) {
    sectPtr->si.channel = 0;
  }
  
  sectPtr->si.validStart = s->validStart;

  sectPtr->si.fftmax = -10000;
  sectPtr->si.fftmin = 10000;
  Snack_InitWindow(sectPtr->si.hamwin, sectPtr->si.winlen, sectPtr->si.fftlen,
		   sectPtr->si.windowType);
  ComputeSection((Tk_Item *)sectPtr);
  
  if (ComputeSectionCoords((Tk_Item *)sectPtr) != TCL_OK) {
    return;
  }
  
  Tk_CanvasEventuallyRedraw(sectPtr->canvas,
655
656
657
658
659
660
661
662




663
664
665
666
667
668
669
766
767
768
769
770
771
772

773
774
775
776
777
778
779
780
781
782
783







-
+
+
+
+







      break;
    }
  }
#endif

  if (CheckFFTlen(interp, sectPtr->si.fftlen) != TCL_OK) return TCL_ERROR;

  if (CheckWinlen(interp, sectPtr->si.winlen) != TCL_OK) return TCL_ERROR;
  if (CheckWinlen(interp, sectPtr->si.winlen, sectPtr->si.fftlen) != TCL_OK)
    return TCL_ERROR;

  if (CheckLPCorder(interp, sectPtr->lpcOrder) != TCL_OK) return TCL_ERROR;

  if (OptSpecified(OPTION_SOUND)) {
    if (sectPtr->newSoundName == NULL) {
      sectPtr->sound = NULL;
      if (sectPtr->id) Snack_RemoveCallback(s, sectPtr->id);
      sectPtr->id = 0;
      sectPtr->si.BufPos = 0;
775
776
777
778
779
780
781
















782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924




925
926
927
928
929
930
931







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+













-
-
-
-







    doCompute = 1;
  }
  sectPtr->si.channel = sectPtr->si.channelSet;
  if (sectPtr->si.nchannels == 1) {
    sectPtr->si.channel = 0;
  }

  if (OptSpecified(OPTION_ANALYSISTYPE)) {
    int len = strlen(sectPtr->analysisTypeStr);

    if (strncasecmp(sectPtr->analysisTypeStr, "lpc", len) == 0) {
      sectPtr->type = 1;
    } else if (strncasecmp(sectPtr->analysisTypeStr, "fft", len) == 0) {
      sectPtr->type = 0;
    } else {
      Tcl_AppendResult(interp, "-type should be FFT or LPC", (char *) NULL);
      return TCL_ERROR;
    }
    doCompute = 1;
  }
  if (OptSpecified(OPTION_LPCORDER)) {
    doCompute = 1;
  }
  if (OptSpecified(OPTION_WINTYPE)) {
    if (GetWindowType(interp, sectPtr->windowTypeStr,
		      &sectPtr->si.windowTypeSet)
	!= TCL_OK) {
      return TCL_ERROR;
    }
    doCompute = 1;
  }
  sectPtr->si.windowType = sectPtr->si.windowTypeSet;

  if (doCompute) {
    sectPtr->nPoints = sectPtr->si.fftlen / 2;
    sectPtr->si.RestartPos = sectPtr->ssmp;
    sectPtr->si.fftmax = -10000;
    sectPtr->si.fftmin = 10000;
    Snack_InitWindow(sectPtr->si.hamwin, sectPtr->si.winlen,
		     sectPtr->si.fftlen, sectPtr->si.windowType);
    ComputeSection((Tk_Item *)sectPtr);
  }

  if (sectPtr->height <= 2) sectPtr->height = 0;

  if (sectPtr->fg == NULL) {
    newGC = None;

Changes to snack/generic/jkCanvSpeg.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
611
612
613
614
615
616
617
618


619
620
621
622
623
624
625
611
612
613
614
615
616
617

618
619
620
621
622
623
624
625
626







-
+
+







      break;
    }
  }
#endif

  if (CheckFFTlen(interp, spegPtr->si.fftlen) != TCL_OK) return TCL_ERROR;

  if (CheckWinlen(interp, spegPtr->si.winlen) != TCL_OK) return TCL_ERROR;
  if (CheckWinlen(interp, spegPtr->si.winlen, spegPtr->si.fftlen) != TCL_OK)
    return TCL_ERROR;

  if (OptSpecified(OPTION_SOUND)) {
    if (spegPtr->newSoundName == NULL) {
      spegPtr->sound = NULL;
      if (spegPtr->id) Snack_RemoveCallback(s, spegPtr->id);
      spegPtr->id = 0;
      spegPtr->si.BufPos = 0;
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
812
813
814
815
816
817
818


819
820
821
822
823
824
825







-
-







    spegPtr->si.spacing = (float)(spegPtr->si.samprate / spegPtr->si.pixpsec);
    nfft = (int)((spegPtr->esmp - spegPtr->ssmp) / spegPtr->si.spacing);
    spegPtr->si.xUnderSamp = 1.0;
    spegPtr->si.RestartPos = spegPtr->ssmp;
    spegPtr->si.fftmax = -10000;
    spegPtr->si.fftmin = 10000;
    spegPtr->si.ssmp = spegPtr->ssmp;
    Snack_InitWindow(spegPtr->si.hamwin, spegPtr->si.winlen,
		     spegPtr->si.fftlen, spegPtr->si.windowType);

    n = ComputeSpeg(&spegPtr->si, nfft);

    if (n < 0) return TCL_OK;
    spegPtr->infft = nfft;
  }

1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265





1266
1267
1268
1269
1270
1271
1272
1248
1249
1250
1251
1252
1253
1254


1255
1256
1257
1258
1259
1260


1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272







-
-






-
-
+
+
+
+
+







  int        ret = nfft;
  int       flag = 0;
  float g = 1.0;
  SnackLinkedFileInfo info;

  if (siPtr->debug > 2) Snack_WriteLogInt("    Enter ComputeSpeg", nfft);

  Snack_InitFFT(fftlen);

  if (storeType != SOUND_IN_MEMORY) {
    if (OpenLinkedFile(siPtr->sound, &info) != TCL_OK) {
      return(0);
    }
  }

  if (siPtr->winlen > siPtr->fftlen)
    winlen = siPtr->fftlen;
  if (winlen > fftlen)  /* should not happen */
    winlen = fftlen;

  Snack_InitFFT(fftlen);
  Snack_InitWindow(siPtr->hamwin, winlen, fftlen, siPtr->windowType);

  siPtr->doneSpeg = 0;
  /*  siPtr->computing = 1;*/

  while (siPtr->frlen <= ((nfft + siPtr->nfft) * fftlen / 2)) {
    if ((siPtr->frame[siPtr->nfrms] = (short *) ckalloc(2*FRAMESIZE)) == NULL)
      return 0;

Changes to snack/generic/jkCanvWave.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
471
472
473
474
475
476
477
478

479
480
481
482
483
484
485
471
472
473
474
475
476
477

478
479
480
481
482
483
484
485







-
+







  if (wavePtr->preCompFile != NULL && wavePtr->sound->readStatus != READ) {
    char *type = NULL;

    if (wavePtr->preSound != NULL) {
      wavePtr->preSound->fcname = NULL;
      Snack_DeleteSound(wavePtr->preSound);
    }
    wavePtr->preSound = Snack_NewSound(100, LIN8, wavePtr->sound->nchannels);
    wavePtr->preSound = Snack_NewSound(200, LIN8, wavePtr->sound->nchannels);
    if (wavePtr->preSound != NULL) {
      wavePtr->preSound->fcname = wavePtr->preCompFile;
      type = LoadSound(wavePtr->preSound, interp, NULL, 0, -1);
      if (wavePtr->preWI != NULL) ckfree((char *)wavePtr->preWI);
      wavePtr->preWI = (WaveItem *) ckalloc(sizeof(WaveItem));
      if (wavePtr->preWI != NULL) {
	wavePtr->preWI->nchannels = wavePtr->preSound->nchannels;
588
589
590
591
592
593
594
595


596
597
598
599
600
601
602
588
589
590
591
592
593
594

595
596
597
598
599
600
601
602
603







-
+
+







	}
      }
      if (wavePtr->cmdPtr != NULL) {
	Snack_ProgressCallback(wavePtr->cmdPtr, interp,
			       "Computing waveform", 1.0);
      }
      if (SaveSound(wavePtr->preSound, interp, wavePtr->preCompFile, NULL,
		0, wavePtr->preSound->length, AIFF_STRING) == TCL_ERROR) {
		    0, NULL, 0, wavePtr->preSound->length, AIFF_STRING) ==
	  TCL_ERROR) {
	if (wavePtr->debug > 2) Snack_WriteLog("    Failed saving waveform\n");
	wavePtr->preCompFile = NULL;
      }
      wavePtr->preWI->bufPos = wavePtr->preSound->length;
      wavePtr->preWI->blocks = wavePtr->preSound->blocks;
      if (wavePtr->storeType != SOUND_IN_MEMORY) {
	CloseLinkedFile(&info);
1431
1432
1433
1434
1435
1436
1437
1438

1439
1440
1441
1442
1443
1444
1445
1432
1433
1434
1435
1436
1437
1438

1439
1440
1441
1442
1443
1444
1445
1446







-
+







	  x1[0] + xo, Tk_CanvasPsY(canvas, (double) 
				   (-y1[0]/scale + yo+ wavePtr->height / 2)));
  Tcl_AppendResult(interp, buffer, (char *) NULL);
  for (i = 1; i < wavePtr->width; i++) {
    sprintf(buffer, "%.15g %.15g lineto\n%.15g %.15g lineto\n",
	    x0[i] + xo, Tk_CanvasPsY(canvas, (double) 
				     (-y0[i]/scale + yo+ wavePtr->height / 2)),
	    x1[i] + xo, Tk_CanvasPsY(canvas, (double) 
	    x1[i] + xo + 0.5, Tk_CanvasPsY(canvas, (double) 
				    (-y1[i]/scale + yo+ wavePtr->height / 2)));
    Tcl_AppendResult(interp, buffer, (char *) NULL);
  }

  if (wavePtr->zeroLevel) {
    sprintf(buffer, "%.15g %.15g moveto\n", (double) xo,
	    Tk_CanvasPsY(canvas, (double) (yo + wavePtr->height / 2)));

Changes to snack/generic/jkFilter.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 2001-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
140
141
142
143
144
145
146
147

148
149
150
151
152
153
154
155


156
157
158
159
160
161
162
140
141
142
143
144
145
146

147
148
149
150
151
152
153


154
155
156
157
158
159
160
161
162







-
+






-
-
+
+







  (f->startProc)(f, si);

  len *= s->nchannels;
  fi = (startpos * s->nchannels) >> FEXP;
  fs = (startpos * s->nchannels) - (fi << FEXP);
  ei = (endpos * s->nchannels) >> FEXP;
  es = (endpos * s->nchannels) - (ei << FEXP);

  
  if (len > 0) {
    for (i = fi; i <= ei; i++) {
      int res;
      
      if (i > fi) fs = 0;
      if (i < ei) {
	inSize  = min(len, FBLKSIZE / s->nchannels) - fs / s->nchannels;
	outSize = min(len, FBLKSIZE / s->nchannels) - fs / s->nchannels;
	inSize  = min(len, (FBLKSIZE - fs) / s->nchannels);
	outSize = min(len, (FBLKSIZE - fs) / s->nchannels);
      } else {
	inSize  = (es - fs) / s->nchannels + 1;
	outSize = (es - fs) / s->nchannels + 1;
      }
      
      (f->flowProc)(f, si, &s->blocks[i][fs], &s->blocks[i][fs],
		    &inSize, &outSize);
437
438
439
440
441
442
443

444
445
446
447




448
449
450
451
452
453
454
455

456
457

458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476

477
478
479
480
481
482
483
437
438
439
440
441
442
443
444




445
446
447
448
449
450
451
452
453
454
455

456
457

458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485







+
-
-
-
-
+
+
+
+







-
+

-
+



















+







mapConfigProc(Snack_Filter f, Tcl_Interp *interp, int objc,
	       Tcl_Obj *CONST objv[])
{
  mapFilter_t mf = (mapFilter_t) f;
  int i;
  double val;

  if (objc > mf->nm) {
  ckfree((char *) mf->m);
  mf->m = (float *) ckalloc(sizeof(float) * objc);
  mf->nm = objc;

    ckfree((char *) mf->m);
    mf->m = (float *) ckalloc(sizeof(float) * objc);
    mf->nm = objc;
  }
  for (i = 0; i < objc; i++) {
    if (Tcl_GetDoubleFromObj(interp, objv[i], &val) != TCL_OK) {
      return TCL_ERROR;
    }
    mf->m[i] = (float) val;
  }

  if (objc == 1 && mf->nm > 1 && mf->si != NULL) {
  if (objc == 1 && mf->nm > 1 && mf->width > 0) {
    /* Special case, duplicate m[0] on the diagonal */
    for (i = 0; i < mf->nm; i = i + mf->si->streamWidth + 1) {
    for (i = 0; i < mf->nm; i = i + mf->width + 1) {
      mf->m[i] = mf->m[0];
    }
  }

  return TCL_OK;
}

Snack_Filter
mapCreateProc(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
  mapFilter_t mf;
  
  mf = (mapFilter_t) ckalloc(sizeof(mapFilter));
  mf->nm = objc;
  if ((mf->m = (float *) ckalloc(sizeof(float) * objc)) == NULL) {
    return (Snack_Filter) NULL;
  }
  mf->ns = 0;
  mf->s = NULL;
  mf->width = 0;

  if (mapConfigProc((Snack_Filter) mf, interp, objc, objv) != TCL_OK) {
    ckfree((char *) mf->m);
    ckfree((char *) mf);
    return (Snack_Filter) NULL;
  }

1220
1221
1222
1223
1224
1225
1226








































































































































































1227
1228
1229
1230
1231
1232
1233
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







  composeCreateProc,
  composeConfigProc,
  composeStartProc,
  composeFlowProc,
  composeFreeProc,
  (Snack_FilterType *) NULL
};

struct fadeFilter {
  configProc *configProc;
  startProc  *startProc;
  flowProc   *flowProc;
  freeProc   *freeProc;
  Tcl_Interp *interp;
  Snack_Filter prev, next;
  Snack_StreamInfo si;
  double     dataRatio;
  int        reserved[4];
  /* private members */
  int        in;
  int        type;
  float      msLength;
  int        length;
  int        pos;
} fadeFilter;

typedef struct fadeFilter *fadeFilter_t;
#define LINEAR 0
#define EXPONENTIAL 1
#define LOGARITHMIC 2

int
fadeConfigProc(Snack_Filter f, Tcl_Interp *interp, int objc,
	       Tcl_Obj *CONST objv[])
{
  fadeFilter_t mf = (fadeFilter_t) f;
  char *typestr;
  double val;

  if (objc == 3) {
    typestr = Tcl_GetStringFromObj(objv[0], NULL);
    if (strcasecmp(typestr, "in") == 0) {
      mf->in = 1;
    } else if (strcasecmp(typestr, "out") == 0) {
      mf->in = 0;
    } else {
      Tcl_SetResult(interp, "bad fade direction, must be in or out",
		    TCL_STATIC);
      return TCL_ERROR;
    }
    
    typestr = Tcl_GetStringFromObj(objv[1], NULL);
    if (strncasecmp(typestr, "linear", 3) == 0) {
      mf->type = LINEAR;
    } else if (strncasecmp(typestr, "exponential", 3) == 0) {
      mf->type = EXPONENTIAL;
    } else if (strncasecmp(typestr, "logarithmic", 3) == 0) {
      mf->type = LOGARITHMIC;
    } else {
      Tcl_SetResult(interp,
	    "bad fade type, must be linear, exponential, or logarithmic",
		    TCL_STATIC);
      return TCL_ERROR;
    }
    
    if (Tcl_GetDoubleFromObj(interp, objv[2], &val) != TCL_OK) {
      return TCL_ERROR;
    }
    mf->msLength = (float) val;
  } else {
    
    /* Arguments need to be at least three */
    
    Tcl_WrongNumArgs(interp, 0, objv, "fade direction type length");
    return TCL_ERROR;
  }
  
  return TCL_OK;
}

Snack_Filter
fadeCreateProc(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
  fadeFilter_t mf;
  
  mf = (fadeFilter_t) ckalloc(sizeof(fadeFilter));

  if (fadeConfigProc((Snack_Filter) mf, interp, objc, objv) != TCL_OK) {
    ckfree((char *) mf);
    return (Snack_Filter) NULL;
  }
  
  return (Snack_Filter) mf;
}

int
fadeStartProc(Snack_Filter f, Snack_StreamInfo si)
{
  fadeFilter_t mf = (fadeFilter_t) f;
  mf->length = (int) (mf->msLength * si->rate / 1000.0);
  mf->pos = 0;
  
  return TCL_OK;
}

#define EULER 2.7182818284590452354 
#define EXP_MINUS_1 0.36787944117

int
fadeFlowProc(Snack_Filter f, Snack_StreamInfo si, float *in, float *out,
	    int *inFrames, int *outFrames)
{
  fadeFilter_t mf = (fadeFilter_t) f;
  int i = 0, fr, wi;
  float factor = 1.0;
  
  for (fr = 0; fr < *inFrames; fr++) {
    if (mf->pos < mf->length) {
      switch (mf->type) {
      case LINEAR:
	if (mf->in) {
	  factor = (float) mf->pos / mf->length;
	} else {
	  factor = (float) (1.0 - (float) mf->pos / mf->length);
	}
	break;
      case EXPONENTIAL:
	if (mf->in) {
	  factor = (float) exp(-10.0+10.0 * mf->pos / mf->length);
	} else {
	  factor = (float) exp(-10.0 * mf->pos / mf->length);
	}
	break;
      case LOGARITHMIC:
	if (mf->in) {
	  factor = (float) (0.5 + 0.5 * log(EXP_MINUS_1 + (EULER - EXP_MINUS_1)
				    * ((float) mf->pos / mf->length)));
	} else {
	  factor = (float) (0.5 + 0.5 * log(EXP_MINUS_1 + (EULER - EXP_MINUS_1)
				    * (1.0-(float) mf->pos / mf->length)));
	}
	break;
      }
    } else {
      factor = 1.0;
    }
    for (wi = 0; wi < si->outWidth; wi++) {
      out[i] = factor * in[i];
      i++;
      mf->pos++;
    }
  }

  *outFrames = *inFrames;

  return TCL_OK;
}

void
fadeFreeProc(Snack_Filter f)
{
  fadeFilter_t mf = (fadeFilter_t) f;

  ckfree((char *) mf);
}

Snack_FilterType snackFadeType = {
  "fade",
  fadeCreateProc,
  fadeConfigProc,
  fadeStartProc,
  fadeFlowProc,
  fadeFreeProc,
  (Snack_FilterType *) NULL
};

void
Snack_CreateFilterType(Snack_FilterType *typePtr)
{
  Snack_FilterType *typePtr2, *prevPtr;

  /*
1246
1247
1248
1249
1250
1251
1252

1253
1254
1255
1256
1257
1258
1259
1260
1261

1262

1263
1264
1265
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437








+









+

+


-
    }
  }
  typePtr->nextPtr = snackFilterTypes;
  snackFilterTypes = typePtr;
}

extern void createSynthesisFilters();
extern void createIIRFilter();

void
SnackCreateFilterTypes(Tcl_Interp *interp)
{
  snackFilterTypes = &snackComposeType;
  snackComposeType.nextPtr = NULL;
  Snack_CreateFilterType(&snackMapType);
  Snack_CreateFilterType(&snackEchoType);
  Snack_CreateFilterType(&snackReverbType);
  Snack_CreateFilterType(&snackFadeType);
  createSynthesisFilters();
  createIIRFilter();
  /*  Snack_CreateFilterType(&snackLowpassType);*/
}

Added snack/generic/jkFilterIIR.c.























































































































































































































































































































































































































































































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
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
 * jkFilterIIR.c --
 *
 *	  Implementation of Snack IIR filters.
 *
 * Copyright (c) 2000 MusicMatch, Inc.  All rights reserved other than
 * as specified here.

 * The authors hereby grant permission to use, copy, modify, distribute,
 * and license this software and its documentation for any purpose, provided
 * that existing copyright notices are retained in all copies and that this
 * notice is included verbatim in any distributions. No written agreement,
 * license, or royalty fee is required for any of the authorized uses.
 * Modifications to this software may be copyrighted by their authors
 * and need not follow the licensing terms described here, provided that
 * the new terms are clearly indicated on the first page of each file where
 * they apply.
 * 
 * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
 * DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
 * IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
 * NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
 * MODIFICATIONS.
 * 
 * GOVERNMENT USE: If you are acquiring this software on behalf of the
 * U.S. government, the Government shall have only "Restricted Rights"
 * in the software and related documentation as defined in the Federal 
 * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
 * are acquiring the software on behalf of the Department of Defense, the
 * software shall be classified as "Commercial Computer Software" and the
 * Government shall have only "Restricted Rights" as defined in Clause
 * 252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
 * authors grant the U.S. Government and others acting in its behalf
 * permission to use and distribute the software in accordance with the
 * terms specified in this license. 
 *
 */

#include "snack.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>

/* Private stuff */

/* far below here for the initialization of this structure */
Snack_FilterType snackIIRType;

/* this structure is a C-coded sub-class of a snack filter */
typedef struct iirFilter {
  configProc *configProc;
  flowProc   *flowProc;
  freeProc   *freeProc;
  Tcl_Interp *interp;
  Snack_Filter prev, next;
  Snack_StreamInfo si;
  double     dataRatio;
  int        reserved[4];
  /* private members */
  int nInTaps;		/* number of numerator taps on filter */
  int nOutTaps;		/* number of denominator taps on filter */
  int width;			/* number of channels in the history.
				   Individual samples are interleaved. */
  double dither;		/* size of triangular dither */
  double noise;		/* size of additive gaussian noise */
  double *itaps;		/* numerator tap weights */
  double *otaps;		/* denominator tap weights */
  int in, out;		/* current position in histories */
  double *inputs;		/* input history for numerator */
  double *outputs;		/* output history for denominator */
} iirFilter, *iirFilter_t;

/*
 * iirConfigProc -- Process the configuration options for an IIR filter.
 * 
 * Arguments:
 *
 * f		Filter structure to configure.
 *
 * interp	Interpreter to use for error messages.
 *
 * objc		Number of options
 *
 * objv		Number of arguments
 * 
 * Returns:
 * TCL_OK or TCL_ERROR as appropriate.  Side effect on f.
 * 
 */
static int
iirConfigProc(Snack_Filter f, Tcl_Interp *interp, int objc,
	       Tcl_Obj *CONST objv[])
{
  int j, n;
  Tcl_Obj **impObj;
  double dither, noise;
  iirFilter_t iir = (iirFilter_t) f;
  
  int arg, arg1 = 0;
  static char *optionStrings[] = {
    "-impulse", "-numerator", "-denominator", "-noise", "-dither", NULL
  };
  enum options {
    IMPULSE, TOP, BOTTOM, NOISE, DITHER
  };
  
  /* The default values have already been set if this is a new
     filter, or the structure has already been configured.  Either way,
     our default course of action here, is to leave everything untouched.
  */
  for (arg = arg1; arg < objc; arg += 2) {
    int index;
    
    /* Tcl_GetIndexFromObj is good to use since it remembers the result
       and makes faster decisions next time */
    if (Tcl_GetIndexFromObj(interp, objv[arg], optionStrings, "option", 0,
			    &index) != TCL_OK) {
      return TCL_ERROR;
    }
    
    switch ((enum options) index) {
      /* size of triangular dithering on output */
    case DITHER:
      if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &dither) != TCL_OK) {
	return TCL_ERROR;
      }
      if (dither < 0) dither = -dither;
      iir->dither = dither;
      break;
      
      /* amount of gaussian noise to add */
    case NOISE:
      if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &noise) != TCL_OK) {
	return TCL_ERROR;
      }
      if (noise < 0) noise = -noise;
      iir->noise = noise;
      break;
      
      /* either the impulse response if this is really an FIR or
	 the numerator of a rational filter of the form
	 y = x P(z)/Q(z).  People who are thinking in terms of
	 FIR's will probably prefer to use -impulse while IIR
	 designers will use -numerator and -denominator.
      */
    case IMPULSE:
    case TOP:
      if (Tcl_ListObjGetElements(interp, objv[arg+1], &n, &impObj) != TCL_OK) {
	return TCL_ERROR;
      }
      
      iir->nInTaps = n;
      iir->itaps = (double *) ckalloc( n * sizeof(iir->itaps[0]) );
      
      for (j = 0; j < n; j++) {
	if (Tcl_GetDoubleFromObj(interp, impObj[j], &iir->itaps[j]) != TCL_OK) {
	  return TCL_ERROR;
	}
      }
      
      break;
      
      /* the denominator of a ratio filter */
    case BOTTOM:
      if (Tcl_ListObjGetElements(interp, objv[arg+1], &n, &impObj) != TCL_OK) {
	return TCL_ERROR;
      }
      
      iir->nOutTaps = n;
      iir->otaps = (double *) ckalloc( n * sizeof(iir->otaps[0]) );
      
      for (j = 0; j < n; j++) {
	if (Tcl_GetDoubleFromObj(interp, impObj[j], &iir->otaps[j]) != TCL_OK) {
	  return TCL_ERROR;
	}
      }
      
      break;
    }
  }
  
  return TCL_OK;
}

/*
 * iirCreateProc -- Create a filter structure.
 * 
 * Arguments:
 *
 * interp		to report errors in
 *
 * objc			number of arguments
 *
 * objv			number of arguments (for configuration)
 * 
 * Returns:
 * A filter structure all filled in and configurated!
 * 
 */

static Snack_Filter
iirCreateProc(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
  iirFilter_t iir;
  
  iir = (iirFilter_t) ckalloc(sizeof(*iir));
  memset(iir, 0, sizeof(*iir));
  
  /* default values set before calling the config */
  iir->dither = 0.75;
  iir->nInTaps = 0;
  iir->nOutTaps = 0;
  
  if (iirConfigProc((Snack_Filter) iir, interp, objc, objv) != TCL_OK) {
    ckfree((char *) iir);
    return (Snack_Filter) NULL;
  }
  
  return (Snack_Filter) iir;
}

/*
 * iirStartProc -- Reinitialize a filter structure.
 * 
 * Arguments:
 *
 * f		The filter to initialize
 *
 * si		Information about a stream.  This is passed to allow the
 *		filter to be customized for the number of channels and such.
 *
 * Returns:
 * TCL_OK or TCL_ERROR as appropriate
 * 
 */

static int
iirStartProc(Snack_Filter f, Snack_StreamInfo si)
{
  int i;
  iirFilter_t iir = (iirFilter_t) f;
  
  if (iir->nInTaps > 0) {
    iir->inputs = (double *) ckalloc(si->outWidth * 
				     iir->nInTaps * sizeof(iir->inputs[0]));
    for (i = 0; i < iir->nInTaps * si->outWidth; i++ ) {
      iir->inputs[i] = 0;
    }
  }
  if (iir->nOutTaps > 0) {
    iir->outputs = (double *) ckalloc(si->outWidth * 
				      iir->nOutTaps * sizeof(iir->outputs[0]));
    for (i = 0; i < iir->nOutTaps * si->outWidth; i++ ) {
      iir->outputs[i] = 0;
    }
  }
  
  iir->in = iir->out = 0;
  
  return TCL_OK;
}

/*
 * name-of-function -- Return a normal random deviate.  The sum of 12
 * 	unit uniform deviates has very close to a normal distribution.
 * 	Changing the sign on 6 of them gives a mean of 0.  This is
 * 	probably slightly faster than the standard method that
 * 	requires half of a sine and half of a log to compute, and it
 * 	is thread safe.  Accuracy is infinitessimally lower.  None of
 * 	these differences matter compared to the fact that I can get
 * 	this one exactly right from memory.
 * 	
 * Arguments:
 *
 * 
 * Returns:
 * A unit normal deviate.
 * 
 */

static double
xdrand48()
{
  return((double)rand()/RAND_MAX);
}

static double
normalDeviate()
{
  return
    xdrand48() + xdrand48() - xdrand48() - xdrand48() +
    xdrand48() + xdrand48() - xdrand48() - xdrand48() +
    xdrand48() + xdrand48() - xdrand48() - xdrand48();
}

/*
 * triangularDeviate -- Return a triangular dither sample.  Adding a
 * 	dither signal from a triangular distribution converts highly
 * 	correlated quantization noise into uncorrelated white noise
 * 	that is generally considered to be less perceptible.
 * 	Theoretically, 1LSB is the optimal size, but in practice,
 * 	somewhat less is actually used.
 * 	
 * Arguments:
 *
 * Returns:
 * A random value from a unit sized triangular distribution.
 * 
 */

static double
triangularDeviate()
{
    return xdrand48() - xdrand48();
}

/*
 * iirFlowProc -- Filter a block of samples, producing a block of
 * 	output samples.
 * 
 * Arguments:
 *
 * f		The filter to apply to the samples.
 *
 * si 		stream info structure.  Should tell us how many channels
 *		to process.  
 *
 * in		Input frame.  An array of (*inFrames) samples.
 *
 * out		Output frame.  An array of samples.
 * 
 * inFrames	A pointer to the number of input frames.  We always
 *		process all of our input, so we never change this.
 * 
 * outFrames	A pointer to the number of output frames.  This must be
 *		at least >= *inFrames.  We return the number of samples
 *		that we process.
 * 
 * Returns:
 * TCL_OK or TCL_ERROR as appropriate
 * 
 * Note:
 */

static int
iirFlowProc(Snack_Filter f, Snack_StreamInfo si, float *in, float *out,
	    int *inFrames, int *outFrames)
{
  iirFilter_t iir = (iirFilter_t) f;
  int i, j, k, wi, iir_in = 0, iir_out = 0;
  double insmp, outsmp;
  
  /* deal with stream width sanity check */
  
  /* so... for each input, process it into the filter */
  
  for (wi = 0; wi < si->outWidth; wi++) {
    iir_in = iir->in;
    iir_out = iir->out;
    for (i = 0; i < *inFrames && i < *outFrames; i++) {
      /* get value and cast to a very safe working copy */
      insmp = (double) in[i*si->outWidth+wi];
      iir->inputs[iir_in*si->outWidth+wi] = insmp;
      
      /* output is initially zero.  We add up the contribution for
	 the input history elements */
      outsmp = 0;
      if (iir->itaps != NULL) {
	/* this is the inner convolution loop.  We should unroll
	   this or something if we care about speed.  Of course,
	   we don't care until we know that the code really works!	   
	   before undertaking a full unrolling, we could just
	   split the loop into two loops to avoid the %
	   operation. 
	*/
	k = iir_in;
	for (j = 0 ; j < iir->nInTaps ; j++) {
	  outsmp += iir->itaps[j] * iir->inputs[k*si->outWidth+wi];
	  k = (k+1)%(iir->nInTaps);
	}
	iir_in = (iir_in+1)%(iir->nInTaps);
      }
      
      if (iir->otaps != NULL) {
	/* now we process the output history.  What happens here
	   is that we rearrange the normal formula from this form
	   
	        P(z)
	   y = ------ x
	        Q(z)
	   
	   to isolate the current output value y_n and put all
	   delayed outputs and all current and delayed inputs
	   together on the RHS.  Thus,
	   
	   q_0 y_n = P(z) x - [Q(z) - q_0] y
	   
	   1  [                                                   ]
	   y_n =  --- [ sum_{i=0..} p_i x_{n-i} - sum_{i=1..} q_i y_{n-i} ]
	   q_0 [                                                   ]
	   
	   
	   So clever, so droll.
	*/
	k = iir_out;
	
	/* note that we skip the 0'th element here */
	for (j = 1 ; j < iir->nOutTaps ; j++) {
	  outsmp -= iir->otaps[j] * iir->outputs[k*si->outWidth+wi];
	  k = (k+1)%(iir->nInTaps);
	}
	iir_out = (iir_out+1)%(iir->nOutTaps);
	
	/* here is where we use the zero'th element */
	outsmp /= iir->otaps[0];
	iir->outputs[iir_out*si->outWidth+wi] = outsmp;
      } 
      out[i*si->outWidth+wi] = (float) (outsmp + iir->noise * normalDeviate()
					+ iir->dither * triangularDeviate());
    }
  }
  iir->in = iir_in;
  iir->out = iir_out;
  
  return TCL_OK;
}

/*
 * iirFreeProc -- Deallocate a filter structure.
 * 
 * Arguments:
 *
 * f		The structure to deallocate.
 * 
 * Returns:
 * void
 */

static void
iirFreeProc(Snack_Filter f)
{
  iirFilter_t iir = (iirFilter_t) f;
  
  if (iir->itaps != NULL) ckfree((void *) iir->itaps);
  if (iir->otaps != NULL) ckfree((void *) iir->otaps);
  if (iir->inputs != NULL) ckfree((void *) iir->inputs);
  if (iir->outputs != NULL) ckfree((void *) iir->outputs);
}

Snack_FilterType snackIIRType = {
  "iir",
  iirCreateProc,
  iirConfigProc,
  iirStartProc,
  iirFlowProc,
  iirFreeProc,
  (Snack_FilterType *) NULL
};

void
createIIRFilter() {
  Snack_CreateFilterType(&snackIIRType);
}

Changes to snack/generic/jkFormatMP3.c.

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


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
-
-
+
+




-
-
-
-
-
-
+
+
+
+
+
+



-
+




-
+






-












-







/* 
 * Copyright (C) 2000 Kare Sjolander <kare@speech.kth.se>
/*
 * Copyright (C) 2000-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *

  This file is derived from

  amp MPEG audio decoder (version 0.7.3)
  (C) Tomislav Uzelac  1996,1997

 
 This file is derived from
 
 amp MPEG audio decoder (version 0.7.3)
 (C) Tomislav Uzelac  1996,1997
 
This software can be used freely for any purpose. It can be distributed
freely, as long as it is not sold commercially without permission from
Tomislav Uzelac <tuzelac@rasip.fer.hr>. However, including this software
on CD_ROMs containing other free software is explicitly permitted even 
on CD_ROMs containing other free software is explicitly permitted even
when a modest distribution fee is charged for the CD, as long as this
software is not a primary selling argument for the CD.

Building derived versions of this software is permitted, as long as they
are not sold commercially without permission from Tomislav Uzelac 
are not sold commercially without permission from Tomislav Uzelac
<tuzelac@rasip.fer.hr>. Any derived versions must be clearly marked as
such, and must be called by a name other than amp. Any derived versions
must retain this copyright notice.
*/

#include <stdlib.h>
#include <tcl.h>
#include "snack.h"
#include "jkFormatMP3.h"
#include <string.h>


static char *mm;
static char *readbuf;
static int bufind = 0;
static Tcl_Channel gch;
static int fool_opt = 0;

extern int useOldObjAPI;

/* "getbits.c" */

static int
_fillbfr(int size)
{
  if (gch != NULL) {
    size = Tcl_Read(gch, (char *) _buffer, size);
64
65
66
67
68
69
70
71

72
73
74
75
76
77
78
62
63
64
65
66
67
68

69
70
71
72
73
74
75
76







-
+







    _buffer[pos+1] << 16 |
    _buffer[pos+2] << 8 |
    _buffer[pos+3];
  ret_value <<= _bptr & 7;
  ret_value >>= 32 - n;
  _bptr += n;
  return ret_value;
}       
}

static int
fillbfr(int advance)
{
  int overflow;

  if (gch != NULL) {
106
107
108
109
110
111
112
113

114
115
116
117
118
119
120
104
105
106
107
108
109
110

111
112
113
114
115
116
117
118







-
+







    buffer[pos+1] << 16 |
    buffer[pos+2] << 8 |
    buffer[pos+3];
  ret_value <<= data & 7;
  ret_value >>= 32 - n;

  return ret_value;
}       
}

static void
sackbits(int n)
{
  data += n;
  data &= 8*BUFFER_SIZE-1;
}
212
213
214
215
216
217
218
219
220


221
222
223
224



225
226
227


228
229
230


231
232
233
234



235
236
237
238
239
240
241
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
236
237
238
239







-
-
+
+

-
-
-
+
+
+

-
-
+
+

-
-
+
+

-
-
-
+
+
+







      info->big_values[gr][ch]=_getbits(9);
      info->global_gain[gr][ch]=_getbits(8);
      if (header->ID) info->scalefac_compress[gr][ch]=_getbits(4);
      else info->scalefac_compress[gr][ch]=_getbits(9);
      info->window_switching_flag[gr][ch]=_getbits(1);

      if (info->window_switching_flag[gr][ch]) {
	info->block_type[gr][ch]=_getbits(2);
	info->mixed_block_flag[gr][ch]=_getbits(1);
        info->block_type[gr][ch]=_getbits(2);
        info->mixed_block_flag[gr][ch]=_getbits(1);

	for (region=0;region<2;region++)
	  info->table_select[gr][ch][region]=_getbits(5);
	info->table_select[gr][ch][2]=0;
        for (region=0;region<2;region++)
          info->table_select[gr][ch][region]=_getbits(5);
        info->table_select[gr][ch][2]=0;

	for (window=0;window<3;window++)
	  info->subblock_gain[gr][ch][window]=_getbits(3);
        for (window=0;window<3;window++)
          info->subblock_gain[gr][ch][window]=_getbits(3);
      } else {
	for (region=0;region<3;region++)
	  info->table_select[gr][ch][region]=_getbits(5);
        for (region=0;region<3;region++)
          info->table_select[gr][ch][region]=_getbits(5);

	info->region0_count[gr][ch]=_getbits(4);
	info->region1_count[gr][ch]=_getbits(3);
	info->block_type[gr][ch]=0;
        info->region0_count[gr][ch]=_getbits(4);
        info->region1_count[gr][ch]=_getbits(3);
        info->block_type[gr][ch]=0;
      }

      if (header->ID) info->preflag[gr][ch]=_getbits(1);
      info->scalefac_scale[gr][ch]=_getbits(1);
      info->count1table_select[gr][ch]=_getbits(1);
    }
  return;
250
251
252
253
254
255
256
257
258


259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280














281
282
283
284
285
286
287
288
289
290
291










292
293
294


295
296
297
298
299
300




301
302

303
304
305
306
307
308




309
310

311
312
313
314
315
316




317
318

319
320
321
322
323
324




325
326

327
328
329
330
331
332
333
334


335
336

337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352






353
354
355
356
357
358
359
360






361
362
363
364
365
366
367
368






369
370
371
372
373
374
375
376
377
378






379
380
381
382
383
384
385
386
387







388
389
390
391
392
393
394






395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417






418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433













434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459

























460
461
462
463
464
465
466
467
468
469
470
471
472

473
474
475
476
477
478
479
248
249
250
251
252
253
254


255
256
257
258
259
260
261
262
263
264














265
266
267
268
269
270
271
272
273
274
275
276
277
278
279










280
281
282
283
284
285
286
287
288
289
290


291
292
293
294




295
296
297
298
299

300
301
302




303
304
305
306
307

308
309
310




311
312
313
314
315

316
317
318




319
320
321
322
323

324
325
326
327
328
329
330


331
332
333

334
335
336
337
338
339
340
341
342
343
344






345
346
347
348
349
350
351
352






353
354
355
356
357
358
359
360






361
362
363
364
365
366
367
368
369
370






371
372
373
374
375
376
377
378







379
380
381
382
383
384
385
386






387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409






410
411
412
413
414
415
416
417
418













419
420
421
422
423
424
425
426
427
428
429
430
431
432

























433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469

470
471
472
473
474
475
476
477







-
-
+
+








-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+

-
-
+
+


-
-
-
-
+
+
+
+

-
+


-
-
-
-
+
+
+
+

-
+


-
-
-
-
+
+
+
+

-
+


-
-
-
-
+
+
+
+

-
+






-
-
+
+

-
+










-
-
-
-
-
-
+
+
+
+
+
+


-
-
-
-
-
-
+
+
+
+
+
+


-
-
-
-
-
-
+
+
+
+
+
+




-
-
-
-
-
-
+
+
+
+
+
+


-
-
-
-
-
-
-
+
+
+
+
+
+
+

-
-
-
-
-
-
+
+
+
+
+
+

















-
-
-
-
-
-
+
+
+
+
+
+



-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+












-
+







decode_scalefactors(struct SIDE_INFO *info,struct AUDIO_HEADER *header,int gr,int ch)
{
  int sfb,window;
  int slen1,slen2;
  int i1,i2,i=0;
  int j,k;
  if (header->ID==1) {
    /* this is MPEG-1 scalefactors format, quite different than 
     * the MPEG-2 format. 
    /* this is MPEG-1 scalefactors format, quite different than
     * the MPEG-2 format.
     */
    slen1=t_slen1[info->scalefac_compress[gr][ch]];
    slen2=t_slen2[info->scalefac_compress[gr][ch]];
    i1=3*slen1;
    i2=3*slen2;

    if (info->window_switching_flag[gr][ch] && info->block_type[gr][ch]==2) {
      if (info->mixed_block_flag[gr][ch]) {
	for (sfb=0;sfb<8;sfb++) {
	  scalefac_l[gr][ch][sfb]=getbits(slen1);
	  i+=slen1;
	}
	for (sfb=3;sfb<6;sfb++) {
	  for (window=0;window<3;window++)
	    scalefac_s[gr][ch][sfb][window]=getbits(slen1);
	  i+=i1;
	}
	for (;sfb<12;sfb++) {
	  for (window=0;window<3;window++)
	    scalefac_s[gr][ch][sfb][window]=getbits(slen2);
	  i+=i2;
	}
        for (sfb=0;sfb<8;sfb++) {
          scalefac_l[gr][ch][sfb]=getbits(slen1);
          i+=slen1;
        }
        for (sfb=3;sfb<6;sfb++) {
          for (window=0;window<3;window++)
            scalefac_s[gr][ch][sfb][window]=getbits(slen1);
          i+=i1;
        }
        for (;sfb<12;sfb++) {
          for (window=0;window<3;window++)
            scalefac_s[gr][ch][sfb][window]=getbits(slen2);
          i+=i2;
        }
      } else { /* !mixed_block_flag */
	for (sfb=0;sfb<6;sfb++) {
	  for (window=0;window<3;window++)
	    scalefac_s[gr][ch][sfb][window]=getbits(slen1);
	  i+=i1;
	}
	for (;sfb<12;sfb++) {
	  for (window=0;window<3;window++)
	    scalefac_s[gr][ch][sfb][window]=getbits(slen2);
	  i+=i2;
	}
        for (sfb=0;sfb<6;sfb++) {
          for (window=0;window<3;window++)
            scalefac_s[gr][ch][sfb][window]=getbits(slen1);
          i+=i1;
        }
        for (;sfb<12;sfb++) {
          for (window=0;window<3;window++)
            scalefac_s[gr][ch][sfb][window]=getbits(slen2);
          i+=i2;
        }
      }
      for (window=0;window<3;window++) 
	scalefac_s[gr][ch][12][window]=0;
      for (window=0;window<3;window++)
        scalefac_s[gr][ch][12][window]=0;
    } else { /* block_type!=2 */
      if ( !info->scfsi[ch][0] || !gr )
	for (sfb=0;sfb<6;sfb++) {
	  scalefac_l[gr][ch][sfb]=getbits(slen1);
	  i+=slen1;
	}
        for (sfb=0;sfb<6;sfb++) {
          scalefac_l[gr][ch][sfb]=getbits(slen1);
          i+=slen1;
        }
      else for (sfb=0;sfb<6;sfb++) {
	scalefac_l[1][ch][sfb]=scalefac_l[0][ch][sfb];
        scalefac_l[1][ch][sfb]=scalefac_l[0][ch][sfb];
      }
      if ( !info->scfsi[ch][1] || !gr )
	for (sfb=6;sfb<11;sfb++) {
	  scalefac_l[gr][ch][sfb]=getbits(slen1);
	  i+=slen1;
	}
        for (sfb=6;sfb<11;sfb++) {
          scalefac_l[gr][ch][sfb]=getbits(slen1);
          i+=slen1;
        }
      else for (sfb=6;sfb<11;sfb++) {
	scalefac_l[1][ch][sfb]=scalefac_l[0][ch][sfb];
        scalefac_l[1][ch][sfb]=scalefac_l[0][ch][sfb];
      }
      if ( !info->scfsi[ch][2] || !gr )
	for (sfb=11;sfb<16;sfb++) {
	  scalefac_l[gr][ch][sfb]=getbits(slen2);
	  i+=slen2;
	}
        for (sfb=11;sfb<16;sfb++) {
          scalefac_l[gr][ch][sfb]=getbits(slen2);
          i+=slen2;
        }
      else for (sfb=11;sfb<16;sfb++) {
	scalefac_l[1][ch][sfb]=scalefac_l[0][ch][sfb];
        scalefac_l[1][ch][sfb]=scalefac_l[0][ch][sfb];
      }
      if ( !info->scfsi[ch][3] || !gr )
	for (sfb=16;sfb<21;sfb++) {
	  scalefac_l[gr][ch][sfb]=getbits(slen2);
	  i+=slen2;
	}
        for (sfb=16;sfb<21;sfb++) {
          scalefac_l[gr][ch][sfb]=getbits(slen2);
          i+=slen2;
        }
      else for (sfb=16;sfb<21;sfb++) {
	scalefac_l[1][ch][sfb]=scalefac_l[0][ch][sfb];
        scalefac_l[1][ch][sfb]=scalefac_l[0][ch][sfb];
      }
      scalefac_l[gr][ch][21]=0;
    }
  } else { /* ID==0 */
    int index = 0,index2,spooky_index;
    int slen[5],nr_of_sfb[5]; /* actually, there's four of each, not five, labelled 1 through 4, but
			       * what's a word of storage compared to one's sanity. so [0] is irellevant.
			       */
                               * what's a word of storage compared to one's sanity. so [0] is irellevant.
                               */

    /* ok, so we got 3 indexes. 
    /* ok, so we got 3 indexes.
     * spooky_index - indicates whether we use the normal set of slen eqs and nr_of_sfb tables
     *                or the one for the right channel of intensity stereo coded frame
     * index        - corresponds to the value of scalefac_compress, as listed in the standard
     * index2       - 0 for long blocks, 1 for short wo/ mixed_block_flag, 2 for short with it
     */
    if ( (header->mode_extension==1 || header->mode_extension==3) && ch==1) { /* right ch... */
      int int_scalefac_compress=info->scalefac_compress[0][ch]>>1;
      intensity_scale=info->scalefac_compress[0][1]&1;
      spooky_index=1;
      if (int_scalefac_compress < 180) {
	slen[1]=int_scalefac_compress/36;
	slen[2]=(int_scalefac_compress%36)/6;
	slen[3]=(int_scalefac_compress%36)%6;
	slen[4]=0;
	info->preflag[0][ch]=0;
	index=0;
        slen[1]=int_scalefac_compress/36;
        slen[2]=(int_scalefac_compress%36)/6;
        slen[3]=(int_scalefac_compress%36)%6;
        slen[4]=0;
        info->preflag[0][ch]=0;
        index=0;
      }
      if ( 180 <= int_scalefac_compress && int_scalefac_compress < 244) {
	slen[1]=((int_scalefac_compress-180)%64)>>4;
	slen[2]=((int_scalefac_compress-180)%16)>>2;
	slen[3]=(int_scalefac_compress-180)%4;
	slen[4]=0;
	info->preflag[0][ch]=0;
	index=1;
        slen[1]=((int_scalefac_compress-180)%64)>>4;
        slen[2]=((int_scalefac_compress-180)%16)>>2;
        slen[3]=(int_scalefac_compress-180)%4;
        slen[4]=0;
        info->preflag[0][ch]=0;
        index=1;
      }
      if ( 244 <= int_scalefac_compress && int_scalefac_compress < 255) {
	slen[1]=(int_scalefac_compress-244)/3;
	slen[2]=(int_scalefac_compress-244)%3;
	slen[3]=0;
	slen[4]=0;
	info->preflag[0][ch]=0;
	index=2;
        slen[1]=(int_scalefac_compress-244)/3;
        slen[2]=(int_scalefac_compress-244)%3;
        slen[3]=0;
        slen[4]=0;
        info->preflag[0][ch]=0;
        index=2;
      }
    } else { /* the usual */
      spooky_index=0;
      if (info->scalefac_compress[0][ch] < 400) {
	slen[1]=(info->scalefac_compress[0][ch]>>4)/5;
	slen[2]=(info->scalefac_compress[0][ch]>>4)%5;
	slen[3]=(info->scalefac_compress[0][ch]%16)>>2;
	slen[4]=info->scalefac_compress[0][ch]%4;
	info->preflag[0][ch]=0;
	index=0;
        slen[1]=(info->scalefac_compress[0][ch]>>4)/5;
        slen[2]=(info->scalefac_compress[0][ch]>>4)%5;
        slen[3]=(info->scalefac_compress[0][ch]%16)>>2;
        slen[4]=info->scalefac_compress[0][ch]%4;
        info->preflag[0][ch]=0;
        index=0;
      }
      if (info->scalefac_compress[0][ch] >= 400 && info->scalefac_compress[0][ch] < 500) {
	slen[1]=((info->scalefac_compress[0][ch]-400)>>2)/5;
	slen[2]=((info->scalefac_compress[0][ch]-400)>>2)%5;
	slen[3]=(info->scalefac_compress[0][ch]-400)%4;
	slen[4]=0;
	info->preflag[0][ch]=0;
	index=1;
      } 
        slen[1]=((info->scalefac_compress[0][ch]-400)>>2)/5;
        slen[2]=((info->scalefac_compress[0][ch]-400)>>2)%5;
        slen[3]=(info->scalefac_compress[0][ch]-400)%4;
        slen[4]=0;
        info->preflag[0][ch]=0;
        index=1;
      }
      if (info->scalefac_compress[0][ch] >= 500 && info->scalefac_compress[0][ch] < 512) {
	slen[1]=(info->scalefac_compress[0][ch]-500)/3;
	slen[2]=(info->scalefac_compress[0][ch]-500)%3;
	slen[3]=0;
	slen[4]=0;
	info->preflag[0][ch]=1;
	index=2;
        slen[1]=(info->scalefac_compress[0][ch]-500)/3;
        slen[2]=(info->scalefac_compress[0][ch]-500)%3;
        slen[3]=0;
        slen[4]=0;
        info->preflag[0][ch]=1;
        index=2;
      }
    }

    if (info->window_switching_flag[0][ch] && info->block_type[0][ch]==2)
      if (info->mixed_block_flag[0][ch]) index2=2;
      else index2=1;
    else index2=0;

    for (j=1;j<=4;j++) nr_of_sfb[j]=spooky_table[spooky_index][index][index2][j-1];

    /* now we'll do some actual scalefactor extraction, and a little more.
     * for each scalefactor band we'll set the value of is_max to indicate
     * illegal is_pos, since with MPEG2 it's not 'hardcoded' to 7.
     */
    if (!info->window_switching_flag[0][ch] || (info->window_switching_flag[0][ch] && info->block_type[0][ch]!=2)) {
      sfb=0;
      for (j=1;j<=4;j++) {
	for (k=0;k<nr_of_sfb[j];k++) {
	  scalefac_l[0][ch][sfb]=getbits(slen[j]);
	  i+=slen[j];
	  if (ch) is_max[sfb]=(1<<slen[j])-1;
	  sfb++;
	}
        for (k=0;k<nr_of_sfb[j];k++) {
          scalefac_l[0][ch][sfb]=getbits(slen[j]);
          i+=slen[j];
          if (ch) is_max[sfb]=(1<<slen[j])-1;
          sfb++;
        }
      }
    } else if (info->block_type[0][ch]==2) {
      if (!info->mixed_block_flag[0][ch]) {
	sfb=0;
	for (j=1;j<=4;j++) {
	  for (k=0;k<nr_of_sfb[j];k+=3) {
	    /* we assume here that nr_of_sfb is divisible by 3. it is.
	     */
	    scalefac_s[0][ch][sfb][0]=getbits(slen[j]);
	    scalefac_s[0][ch][sfb][1]=getbits(slen[j]);
	    scalefac_s[0][ch][sfb][2]=getbits(slen[j]);
	    i+=3*slen[j];
	    if (ch) is_max[sfb+6]=(1<<slen[j])-1;
	    sfb++;
	  }
	}
        sfb=0;
        for (j=1;j<=4;j++) {
          for (k=0;k<nr_of_sfb[j];k+=3) {
            /* we assume here that nr_of_sfb is divisible by 3. it is.
             */
            scalefac_s[0][ch][sfb][0]=getbits(slen[j]);
            scalefac_s[0][ch][sfb][1]=getbits(slen[j]);
            scalefac_s[0][ch][sfb][2]=getbits(slen[j]);
            i+=3*slen[j];
            if (ch) is_max[sfb+6]=(1<<slen[j])-1;
            sfb++;
          }
        }
      } else {
	/* what we do here is:
	 * 1. assume that for every fs, the two lowest subbands are equal to the
	 *    six lowest scalefactor bands for long blocks/MPEG2. they are.
	 * 2. assume that for every fs, the two lowest subbands are equal to the
	 *    three lowest scalefactor bands for short blocks. they are.
	 */
	sfb=0;
	for (k=0;k<6;k++) {
	  scalefac_l[0][ch][sfb]=getbits(slen[1]);
	  i+=slen[j];
	  if (ch) is_max[sfb]=(1<<slen[1])-1;
	  sfb++;
	}
	nr_of_sfb[1]-=6;
	sfb=3;
	for (j=1;j<=4;j++) {
	  for (k=0;k<nr_of_sfb[j];k+=3) {
	    scalefac_s[0][ch][sfb][0]=getbits(slen[j]);
	    scalefac_s[0][ch][sfb][1]=getbits(slen[j]);
	    scalefac_s[0][ch][sfb][2]=getbits(slen[j]);
	    i+=3*slen[j];
	    if (ch) is_max[sfb+6]=(1<<slen[j])-1;
	    sfb++;
	  }
	}
        /* what we do here is:
         * 1. assume that for every fs, the two lowest subbands are equal to the
         *    six lowest scalefactor bands for long blocks/MPEG2. they are.
         * 2. assume that for every fs, the two lowest subbands are equal to the
         *    three lowest scalefactor bands for short blocks. they are.
         */
        sfb=0;
        for (k=0;k<6;k++) {
          scalefac_l[0][ch][sfb]=getbits(slen[1]);
          i+=slen[j];
          if (ch) is_max[sfb]=(1<<slen[1])-1;
          sfb++;
        }
        nr_of_sfb[1]-=6;
        sfb=3;
        for (j=1;j<=4;j++) {
          for (k=0;k<nr_of_sfb[j];k+=3) {
            scalefac_s[0][ch][sfb][0]=getbits(slen[j]);
            scalefac_s[0][ch][sfb][1]=getbits(slen[j]);
            scalefac_s[0][ch][sfb][2]=getbits(slen[j]);
            i+=3*slen[j];
            if (ch) is_max[sfb+6]=(1<<slen[j])-1;
            sfb++;
          }
        }
      }
    }
  }
  return i;
}

/* this is for huffman decoding, but inlined funcs have to go first
 */
static int
_qsign(int x,int *q)
{
  int ret_value=0,i;
  for (i=3;i>=0;i--) 
  for (i=3;i>=0;i--)
    if ((x>>i) & 1) {
      if (getbits(1)) *q++=-1;
      else *q++=1;
      ret_value++;
    }
    else *q++=0;
  return ret_value;
502
503
504
505
506
507
508
509

510
511
512
513
514
515

516
517

518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535


536
537
538
539


540
541
542
543


544
545
546
547


548
549
550
551
552
553
554
555
556
557

558
559
560
561
562
563
564


565
566
567
568

569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587

588
589
590
591
592
593
594
500
501
502
503
504
505
506

507
508
509
510
511
512

513
514

515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531


532
533
534
535


536
537
538
539


540
541
542
543


544
545
546
547
548
549
550
551
552
553
554

555
556
557
558
559
560


561
562
563
564
565

566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584

585
586
587
588
589
590
591
592







-
+





-
+

-
+
















-
-
+
+


-
-
+
+


-
-
+
+


-
-
+
+









-
+





-
-
+
+



-
+


















-
+







     */
    r[0]=t_l[info->region0_count[gr][ch]] + 1;
    if (r[0] > big_value)
      r[0]=r[1]=big_value;
    else {
      r[1]=t_l[ info->region0_count[gr][ch] + info->region1_count[gr][ch] + 1 ] + 1;
      if (r[1] > big_value)
	r[1]=big_value;
        r[1]=big_value;
    }
    r[2]=big_value;

  } else {

    if (info->block_type[gr][ch]==2 && info->mixed_block_flag[gr][ch]==0) 
    if (info->block_type[gr][ch]==2 && info->mixed_block_flag[gr][ch]==0)
      r[0]=3*(t_s[2]+1);
    else 
    else
      r[0]=t_l[7]+1;

    if (r[0] > big_value)
      r[0]=big_value;

    r[1]=r[2]=big_value;
  }

  l=0; cnt=0;
  for (i=0;i<3;i++) {
    for (;l<r[i];l+=2) {
      int j = linbits[i];

      cnt+=huffman_decode(tr[i],&x,&y);

      if (x==15 && j>0) {
	x+=getbits(j);
	cnt+=j;
        x+=getbits(j);
        cnt+=j;
      }
      if (x) {
	if (getbits(1)) x=-x;
	cnt++;
        if (getbits(1)) x=-x;
        cnt++;
      }
      if (y==15 && j>0) {
	y+=getbits(j);
	cnt+=j;
        y+=getbits(j);
        cnt+=j;
      }
      if (y) {
	if (getbits(1)) y=-y;
	cnt++;
        if (getbits(1)) y=-y;
        cnt++;
      }

      /*      if (SHOW_HUFFBITS) printf(" (%d,%d) %d\n",x,y, SHOW_HUFFBITS);*/
      is[ch][l]=x;
      is[ch][l+1]=y;
    }
  }
  /*if (cnt > info->part2_3_length[gr][ch] - ssize )
        if (SHOW_HUFFMAN_ERRORS) printf(" ERROR in BIGVALUES %d\n",\
	  cnt-info->part2_3_length[gr][ch]+ssize);*/
          cnt-info->part2_3_length[gr][ch]+ssize);*/
  while ((cnt < info->part2_3_length[gr][ch]-ssize) && (l<576)) {
    cnt+=huffman_decode(tr[3],&x,&y);
    cnt+=_qsign(x,q);
    for (i=0;i<4;i++) is[ch][l+i]=q[i]; /* ziher je ziher, is[578]*/
    l+=4;
    /*    if (SHOW_HUFFBITS) 
	  printf(" (%d,%d,%d,%d)\n",q[0],q[1],q[2],q[3]);*/
    /*    if (SHOW_HUFFBITS)
          printf(" (%d,%d,%d,%d)\n",q[0],q[1],q[2],q[3]);*/
  }
  /*
  if (SHOW_HUFFMAN_ERRORS) {
    if (cnt > info->part2_3_length[gr][ch] - ssize ) 
    if (cnt > info->part2_3_length[gr][ch] - ssize )
      printf ( "%d BITS DISCARDED\n",info->part2_3_length[gr][ch]-cnt+i-ssize);
    else if (cnt < info->part2_3_length[gr][ch] - ssize )
      printf(" %d BITS NOT USED\n",cnt-info->part2_3_length[gr][ch]+ssize);
      }*/
  /*  set position to start of the next gr/ch
   */
  if (cnt != info->part2_3_length[gr][ch] - ssize ) {
    data-=cnt-(info->part2_3_length[gr][ch] - ssize);
    data&= 8*BUFFER_SIZE - 1;
  }
  if (l<576) non_zero[ch]=l;
  else non_zero[ch]=576;
  /* zero out everything else
   */
  for (;l<576;l++) is[ch][l]=0;
  return 1;
}

/* 
/*
 * fras == Formula for Requantization and All Scaling **************************
 */
static float
fras_l(int sfb,int global_gain,int scalefac_scale,int scalefac,int preflag)
{
  int a,scale;
  if (scalefac_scale) scale=2;
661
662
663
664
665
666
667
668
669
670
671
672
673






674
675
676
677
678

679
680
681
682
683
684
685
686
687
688
689
690
691











692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713











714
715
716
717
718
719
720
721
722
723
724
725

726
727
728


729
730
731
732
733
734
735
659
660
661
662
663
664
665






666
667
668
669
670
671
672
673
674
675

676
677
678











679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700











701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722

723
724


725
726
727
728
729
730
731
732
733







-
-
-
-
-
-
+
+
+
+
+
+




-
+


-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+











-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+











-
+

-
-
+
+







       */
      int window,window_len,preflag=0; /* pretab is all zero in this low frequency area */
      int scalefac=scalefac_l[gr][ch][0];

      l=0;sfb=0;
      a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
      while (l<36) {
	xr[ch][0][l]=fras2(is[ch][l],a);
	if (l==t_l[sfb]) {
	  scalefac=scalefac_l[gr][ch][++sfb];
	  a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
	}
	l++;
        xr[ch][0][l]=fras2(is[ch][l],a);
        if (l==t_l[sfb]) {
          scalefac=scalefac_l[gr][ch][++sfb];
          a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
        }
        l++;
      }
      /*
       * requantize_mono - mixed blocks/short block part *********************
       */
      sfb=3; 
      sfb=3;
      window_len=t_s[sfb]-t_s[sfb-1];
      while (l<non_zero[ch]) {
	for (window=0;window<3;window++) {
	  int scalefac=scalefac_s[gr][ch][sfb][window];
	  int subblock_gain=info->subblock_gain[gr][ch][window];
	  a=fras_s(global_gain,subblock_gain,scalefac_scale,scalefac);
	  for (i=0;i<window_len;i++) {
	    xr[ch][0][t_reorder[header->ID][sfreq][l]]=fras2(is[ch][l],a);
	    l++;
	  }
	}
	sfb++;
	window_len=t_s[sfb]-t_s[sfb-1];
        for (window=0;window<3;window++) {
          int scalefac=scalefac_s[gr][ch][sfb][window];
          int subblock_gain=info->subblock_gain[gr][ch][window];
          a=fras_s(global_gain,subblock_gain,scalefac_scale,scalefac);
          for (i=0;i<window_len;i++) {
            xr[ch][0][t_reorder[header->ID][sfreq][l]]=fras2(is[ch][l],a);
            l++;
          }
        }
        sfb++;
        window_len=t_s[sfb]-t_s[sfb-1];
      }
      while (l<576) xr[ch][0][t_reorder[header->ID][sfreq][l++]]=0;
    } else {
      /*
       * requantize mono - short blocks **************************************
       */
      int window,window_len;

      sfb=0; l=0;
      window_len=t_s[0]+1;
      while (l<non_zero[ch]) {
	for (window=0;window<3;window++) {
	  int scalefac=scalefac_s[gr][ch][sfb][window];
	  int subblock_gain=info->subblock_gain[gr][ch][window];
	  float a=fras_s(global_gain,subblock_gain,scalefac_scale,scalefac);
	  for (i=0;i<window_len;i++) {
	    xr[ch][0][t_reorder[header->ID][sfreq][l]]=fras2(is[ch][l],a);
	    l++;
	  }
	}
	sfb++;
	window_len=t_s[sfb]-t_s[sfb-1];
        for (window=0;window<3;window++) {
          int scalefac=scalefac_s[gr][ch][sfb][window];
          int subblock_gain=info->subblock_gain[gr][ch][window];
          float a=fras_s(global_gain,subblock_gain,scalefac_scale,scalefac);
          for (i=0;i<window_len;i++) {
            xr[ch][0][t_reorder[header->ID][sfreq][l]]=fras2(is[ch][l],a);
            l++;
          }
        }
        sfb++;
        window_len=t_s[sfb]-t_s[sfb-1];
      }
      while (l<576) xr[ch][0][t_reorder[header->ID][sfreq][l++]]=0;
    }
  else {
    /* long blocks */
    int preflag=info->preflag[gr][ch];
    int scalefac=scalefac_l[gr][ch][0];

    sfb=0; l=0;
    a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
    while (l<non_zero[ch]) {
      xr[ch][0][l]=fras2(is[ch][l],a); 
      xr[ch][0][l]=fras2(is[ch][l],a);
      if (l==t_l[sfb]) {
	scalefac=scalefac_l[gr][ch][++sfb];
	a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
        scalefac=scalefac_l[gr][ch][++sfb];
        a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
      }
      l++;
    }
    while (l<576) xr[ch][0][l++]=0;
  }
}

748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
















771
772
773
774
775
776
777
778
779
780
781
782







783
784
785
786
787
788
789
746
747
748
749
750
751
752
















753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773







774
775
776
777
778
779
780
781
782
783
784
785
786
787







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+





-
-
-
-
-
-
-
+
+
+
+
+
+
+







    if (info->window_switching_flag[gr][0] && info->block_type[gr][0]==2) {

      /* find that isbound!
       */
      tmp=non_zero[1];
      sfb=0; while ((3*t_s[sfb]+2) < tmp  && sfb < 12) sfb++;
      while ((isbound[0]<0 || isbound[1]<0 || isbound[2]<0) && !(info->mixed_block_flag[gr][0] && sfb<3) && sfb) {
	for (window=0;window<3;window++) {
	  if (sfb==0) {
	    window_len=t_s[0]+1;
	    tmp=(window+1)*window_len - 1;
	  } else {
	    window_len=t_s[sfb]-t_s[sfb-1];
	    tmp=(3*t_s[sfb-1]+2) + (window+1)*window_len;
	  }
	  if (isbound[window] < 0)
	    for (i=0;i<window_len;i++)
	      if (is[1][tmp--] != 0) {
		isbound[window]=t_s[sfb]+1; 
		break;
	      }
	}
	sfb--;
        for (window=0;window<3;window++) {
          if (sfb==0) {
            window_len=t_s[0]+1;
            tmp=(window+1)*window_len - 1;
          } else {
            window_len=t_s[sfb]-t_s[sfb-1];
            tmp=(3*t_s[sfb-1]+2) + (window+1)*window_len;
          }
          if (isbound[window] < 0)
            for (i=0;i<window_len;i++)
              if (is[1][tmp--] != 0) {
                isbound[window]=t_s[sfb]+1;
                break;
              }
        }
        sfb--;
      }

      /* mixed block magic now...
       */
      if (sfb==2 && info->mixed_block_flag[gr][0]) {
	if (isbound[0]<0 && isbound[1]<0 && isbound[2]<0) {
	  tmp=35;
	  while (is[1][tmp] == 0) tmp--;
	  sfb=0; while (t_l[sfb] < tmp  && sfb < 21) sfb++;
	  isbound[0]=isbound[1]=isbound[2]=t_l[sfb]+1;
	} else for (window=0;window<3;window++) 
	  if (isbound[window]<0) isbound[window]=36;
        if (isbound[0]<0 && isbound[1]<0 && isbound[2]<0) {
          tmp=35;
          while (is[1][tmp] == 0) tmp--;
          sfb=0; while (t_l[sfb] < tmp  && sfb < 21) sfb++;
          isbound[0]=isbound[1]=isbound[2]=t_l[sfb]+1;
        } else for (window=0;window<3;window++)
          if (isbound[window]<0) isbound[window]=36;
      }
      if (header->ID==1) isbound[0]=isbound[1]=isbound[2]=max(isbound[0],max(isbound[1],isbound[2]));

      /* just how many imdcts?
       */
      tmp=non_zero[0];
      sfb=0; while ((3*t_s[sfb]+2) < tmp && sfb < 12) sfb++;
804
805
806
807
808
809
810
811
812


813
814
815
816
817
818
819
802
803
804
805
806
807
808


809
810
811
812
813
814
815
816
817







-
-
+
+







  } else {

    /* intensity stereo is, regretably, turned off
     */
    ms_flag=1;

    /* i really put a lot of work in this, but it still looks like shit (works, though)
     */ 
    if (!info->window_switching_flag[gr][0] || (info->window_switching_flag[gr][0] && info->block_type[gr][0]!=2)) 
     */
    if (!info->window_switching_flag[gr][0] || (info->window_switching_flag[gr][0] && info->block_type[gr][0]!=2))
      isbound[0]=isbound[1]=isbound[2]=(max(non_zero[0],non_zero[1]));
    else isbound[0]=isbound[1]=isbound[2]=576;

    if (info->window_switching_flag[gr][0] && info->block_type[gr][0]==2) {
      /* should do for mixed blocks too, though i havent tested... */
      tmp=(max(non_zero[0],non_zero[1]))/3;
      sfb=0; while (t_s[sfb]<tmp && sfb<12) sfb++;
869
870
871
872
873
874
875
876

877
878
879
880
881
882
883
867
868
869
870
871
872
873

874
875
876
877
878
879
880
881







-
+







  float ftmp,Mi,Si;
  if (l>=576) return;
  if ((is_pos != IS_ILLEGAL) && (header->ID==1)) {
    ftmp=fras2(is[0][l],a[0]);
    xr[0][0][l]=(1-t_is[is_pos])*ftmp;
    xr[1][0][l]=t_is[is_pos]*ftmp;
    return;
  } 
  }

  if ((is_pos != IS_ILLEGAL) && (header->ID==0)) {
    ftmp=fras2(is[0][l],a[0]);
    if (is_pos&1) {
      xr[0][0][l]= t_is2[intensity_scale][(is_pos+1)>>1] * ftmp;
      xr[1][0][l]= ftmp;
    } else {
913
914
915
916
917
918
919
920

921
922

923
924
925
926
927
928
929
930
931
932
933


934
935
936
937
938
939
940
941
942
943
944
945
946
947










948
949

950
951
952
953
954
955
956
957







958
959

960
961
962
963
964
965
966
967
968
969
970
971
972





973
974
975
976
977
978
979
980
981
982
983
984
985
986
987














988
989
990
991
992
993
994
995







996
997
998
999
1000



1001
1002

1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017





1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029











1030
1031
1032


1033
1034
1035
1036
1037
1038
1039







1040
1041
1042
1043
1044



1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060

1061
1062
1063
1064
1065
1066
1067
1068





1069
1070
1071
1072
1073
1074
1075
1076
1077



1078
1079
1080
1081
1082
1083
1084
1085




1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101

1102
1103

1104
1105
1106
1107
1108
1109
1110
911
912
913
914
915
916
917

918
919

920
921
922
923
924
925
926
927
928
929


930
931
932
933
934
935










936
937
938
939
940
941
942
943
944
945
946

947
948







949
950
951
952
953
954
955
956

957
958
959
960
961
962
963
964
965





966
967
968
969
970
971














972
973
974
975
976
977
978
979
980
981
982
983
984
985
986







987
988
989
990
991
992
993
994
995



996
997
998
999

1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010





1011
1012
1013
1014
1015
1016











1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028


1029
1030
1031






1032
1033
1034
1035
1036
1037
1038
1039
1040



1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058

1059
1060
1061
1062





1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073



1074
1075
1076
1077
1078
1079
1080




1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099

1100
1101

1102
1103
1104
1105
1106
1107
1108
1109







-
+

-
+









-
-
+
+




-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+

-
+

-
-
-
-
-
-
-
+
+
+
+
+
+
+

-
+








-
-
-
-
-
+
+
+
+
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
-
-
-
-
-
+
+
+
+
+
+
+


-
-
-
+
+
+

-
+










-
-
-
-
-
+
+
+
+
+

-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+

-
-
+
+

-
-
-
-
-
-
+
+
+
+
+
+
+


-
-
-
+
+
+















-
+



-
-
-
-
-
+
+
+
+
+






-
-
-
+
+
+




-
-
-
-
+
+
+
+















-
+

-
+







  int sfreq=header->sampling_frequency;
  int id = header->ID;
  float a[2];

  global_gain=info->global_gain[gr];
  scalefac_scale=info->scalefac_scale[gr];

  if (info->window_switching_flag[gr][0] && info->block_type[gr][0]==2)  
  if (info->window_switching_flag[gr][0] && info->block_type[gr][0]==2)
    if (info->mixed_block_flag[gr][0]) {
      /* 
      /*
       * mixed blocks w/stereo processing - long block part ******************
       */
      int window,window_len;
      int preflag[2]={0,0};

      ms_flag=find_isbound(isbound,gr,info,header);

      sfb=0; l=0;
      for (ch=0;ch<2;ch++) {
	scalefac[ch]=scalefac_l[gr][ch][0];
	a[ch]=fras_l(0,global_gain[ch],scalefac_scale[ch],scalefac[ch],preflag[ch]);
        scalefac[ch]=scalefac_l[gr][ch][0];
        a[ch]=fras_l(0,global_gain[ch],scalefac_scale[ch],scalefac[ch],preflag[ch]);
      }


      while (l<36) {
	int is_pos;
	if (l<isbound[0]) is_pos=IS_ILLEGAL;
	else {
	  is_pos=scalefac[1];
	  if (id==1) { /* MPEG1 */
	    if (is_pos==7) is_pos=IS_ILLEGAL;
	    else /* MPEG2 */
	      if (is_pos==is_max[sfb]) is_pos=IS_ILLEGAL;
	  }
	}
        int is_pos;
        if (l<isbound[0]) is_pos=IS_ILLEGAL;
        else {
          is_pos=scalefac[1];
          if (id==1) { /* MPEG1 */
            if (is_pos==7) is_pos=IS_ILLEGAL;
            else /* MPEG2 */
              if (is_pos==is_max[sfb]) is_pos=IS_ILLEGAL;
          }
        }

	stereo_l(l,a,ms_flag,is_pos,header);
        stereo_l(l,a,ms_flag,is_pos,header);

	if (l==t_l[sfb]) {
	  sfb++;
	  for (ch=0;ch<2;ch++) {
	    scalefac[ch]=scalefac_l[gr][ch][sfb];
	    a[ch]=fras_l(sfb,global_gain[ch],scalefac_scale[ch],scalefac[ch],preflag[ch]);
	  }
	}
        if (l==t_l[sfb]) {
          sfb++;
          for (ch=0;ch<2;ch++) {
            scalefac[ch]=scalefac_l[gr][ch][sfb];
            a[ch]=fras_l(sfb,global_gain[ch],scalefac_scale[ch],scalefac[ch],preflag[ch]);
          }
        }

	l++;
        l++;
      }
      /*
       * mixed blocks w/stereo processing - short block part *****************
       */
      sfb=3;
      window_len=t_s[sfb]-t_s[sfb-1];

      while (l<(max(non_zero[0],non_zero[1]))) {
	for (window=0;window<3;window++) {
	  subblock_gain[0]=info->subblock_gain[gr][0][window];
	  subblock_gain[1]=info->subblock_gain[gr][1][window];
	  scalefac[0]=scalefac_s[gr][0][sfb][window];
	  scalefac[1]=scalefac_s[gr][1][sfb][window];
        for (window=0;window<3;window++) {
          subblock_gain[0]=info->subblock_gain[gr][0][window];
          subblock_gain[1]=info->subblock_gain[gr][1][window];
          scalefac[0]=scalefac_s[gr][0][sfb][window];
          scalefac[1]=scalefac_s[gr][1][sfb][window];

	  if (t_s[sfb] < isbound[window]) {
	    is_pos=IS_ILLEGAL;
	    a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
	    a[1]=fras_s(global_gain[1],subblock_gain[1],scalefac_scale[1],scalefac[1]);
	  } else {
	    is_pos=scalefac[1];
	    if (id==1) { /* MPEG1 */
	      if (is_pos==7) is_pos=IS_ILLEGAL;
	      else /* MPEG2 */
		if (is_pos==is_max[sfb+6]) is_pos=IS_ILLEGAL;
	    }
 
	    a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
	  }
          if (t_s[sfb] < isbound[window]) {
            is_pos=IS_ILLEGAL;
            a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
            a[1]=fras_s(global_gain[1],subblock_gain[1],scalefac_scale[1],scalefac[1]);
          } else {
            is_pos=scalefac[1];
            if (id==1) { /* MPEG1 */
              if (is_pos==7) is_pos=IS_ILLEGAL;
              else /* MPEG2 */
                if (is_pos==is_max[sfb+6]) is_pos=IS_ILLEGAL;
            }

            a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
          }

	  for (i=0;i<window_len && l < 576;i++) {
	    stereo_s(l,a,t_reorder[id][sfreq][l],ms_flag,is_pos,header);
	    l++;
	  }
	}
	sfb++;
	window_len=t_s[sfb]-t_s[sfb-1];
          for (i=0;i<window_len && l < 576;i++) {
            stereo_s(l,a,t_reorder[id][sfreq][l],ms_flag,is_pos,header);
            l++;
          }
        }
        sfb++;
        window_len=t_s[sfb]-t_s[sfb-1];
      }
      while (l<576) {
	int reorder = t_reorder[id][sfreq][l++];
                          
	xr[0][0][reorder]=xr[1][0][reorder]=0;
        int reorder = t_reorder[id][sfreq][l++];

        xr[0][0][reorder]=xr[1][0][reorder]=0;
      }
    } else {                                                                       
    } else {
      /*
       * requantize_ms - short blocks w/stereo processing ********************
       */
      int window,window_len;

      ms_flag=find_isbound(isbound,gr,info,header);
      sfb=0; l=0;
      window_len=t_s[0]+1;

      while (l<(max(non_zero[0],non_zero[1]))) {
	for (window=0;window<3;window++) {
	  subblock_gain[0]=info->subblock_gain[gr][0][window];
	  subblock_gain[1]=info->subblock_gain[gr][1][window];
	  scalefac[0]=scalefac_s[gr][0][sfb][window];
	  scalefac[1]=scalefac_s[gr][1][sfb][window];
        for (window=0;window<3;window++) {
          subblock_gain[0]=info->subblock_gain[gr][0][window];
          subblock_gain[1]=info->subblock_gain[gr][1][window];
          scalefac[0]=scalefac_s[gr][0][sfb][window];
          scalefac[1]=scalefac_s[gr][1][sfb][window];

	  if (t_s[sfb] < isbound[window]) {
	    is_pos=IS_ILLEGAL;
	    a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
	    a[1]=fras_s(global_gain[1],subblock_gain[1],scalefac_scale[1],scalefac[1]);
	  } else {
	    is_pos=scalefac[1];
	    if (id==1) { /* MPEG1 */
	      if (is_pos==7) is_pos=IS_ILLEGAL;
	      else /* MPEG2 */
		if (is_pos==is_max[sfb+6]) is_pos=IS_ILLEGAL;
	    }
          if (t_s[sfb] < isbound[window]) {
            is_pos=IS_ILLEGAL;
            a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
            a[1]=fras_s(global_gain[1],subblock_gain[1],scalefac_scale[1],scalefac[1]);
          } else {
            is_pos=scalefac[1];
            if (id==1) { /* MPEG1 */
              if (is_pos==7) is_pos=IS_ILLEGAL;
              else /* MPEG2 */
                if (is_pos==is_max[sfb+6]) is_pos=IS_ILLEGAL;
            }

	    a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
	  }
            a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
          }

	  for (i=0;i<window_len && l < 576;i++) {
	    stereo_s(l,a,t_reorder[id][sfreq][l],ms_flag,is_pos,header);
	    l++;
	  }
	}
	window_len=-t_s[sfb]+t_s[++sfb];
          for (i=0;i<window_len && l < 576;i++) {
            stereo_s(l,a,t_reorder[id][sfreq][l],ms_flag,is_pos,header);
            l++;
          }
        }
        window_len=-t_s[sfb]+t_s[sfb+1];
        sfb++;
      }
      while (l<576) {
	int reorder = t_reorder[id][sfreq][l++];
                          
	xr[0][0][reorder]=xr[1][0][reorder]=0;
        int reorder = t_reorder[id][sfreq][l++];

        xr[0][0][reorder]=xr[1][0][reorder]=0;
      }
    }
  else {
    /*
     * long blocks w/stereo processing *************************************
     */
    int *preflag=info->preflag[gr];

    ms_flag=find_isbound(isbound,gr,info,header);

    sfb=0; l=0;
    scalefac[0]=scalefac_l[gr][0][sfb];
    a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
    scalefac[1]=scalefac_l[gr][1][sfb];
    a[1]=fras_l(sfb,global_gain[1],scalefac_scale[1],scalefac[1],preflag[1]);
    while (l< isbound[0]) {   
    while (l< isbound[0]) {
      int is_pos=IS_ILLEGAL;
      stereo_l(l,a,ms_flag,is_pos,header);
      if (l==t_l[sfb]) {
	sfb++;
	scalefac[0]=scalefac_l[gr][0][sfb];
	a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
	scalefac[1]=scalefac_l[gr][1][sfb];
	a[1]=fras_l(sfb,global_gain[1],scalefac_scale[1],scalefac[1],preflag[1]);
        sfb++;
        scalefac[0]=scalefac_l[gr][0][sfb];
        a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
        scalefac[1]=scalefac_l[gr][1][sfb];
        a[1]=fras_l(sfb,global_gain[1],scalefac_scale[1],scalefac[1],preflag[1]);
      }
      l++;
    }
    while (l<(max(non_zero[0],non_zero[1]))) {
      int is_pos=scalefac[1];
      if (id==1) { /* MPEG1 */
	if (is_pos==7) is_pos=IS_ILLEGAL;
	else /* MPEG2 */
	  if (is_pos==is_max[sfb]) is_pos=IS_ILLEGAL;
        if (is_pos==7) is_pos=IS_ILLEGAL;
        else /* MPEG2 */
          if (is_pos==is_max[sfb]) is_pos=IS_ILLEGAL;
      }

      stereo_l(l,a,ms_flag,is_pos,header);
      if (l==t_l[sfb]) {
	sfb++;
	scalefac[0]=scalefac_l[gr][0][sfb];
	scalefac[1]=scalefac_l[gr][1][sfb];
	a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
        sfb++;
        scalefac[0]=scalefac_l[gr][0][sfb];
        scalefac[1]=scalefac_l[gr][1][sfb];
        a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
      }
      l++;
    }
    while (l<576) {
      xr[0][0][l]=0;
      xr[1][0][l]=0;
      l++;
    }
  }
}

#ifdef WIN
#pragma optimize("", on)
#endif

/* 
/*
 * antialiasing butterflies
 * 
 *
 */
static void
alias_reduction(int ch)
{
  int sb,i;

  for (sb=1;sb<32;sb++) {
1145
1146
1147
1148
1149
1150
1151
1152

1153
1154
1155
1156
1157
1158
1159

1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175

1176
1177

1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188




1189
1190
1191
1192
1193
1194
1195
1144
1145
1146
1147
1148
1149
1150

1151
1152
1153
1154
1155
1156
1157

1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173

1174
1175

1176
1177
1178
1179
1180
1181
1182
1183




1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194







-
+






-
+















-
+

-
+







-
-
-
-
+
+
+
+








  /* check for an immediate hit, so we can decode those short codes very f
     ast
     */
  if ((*h_tab>>(32-len)) != (chunk>>(19-len))) {
    if (chunk >> (19-NC_O) < N_CUE-1)
      lag=(h_cue[tbl][(chunk >> (19-NC_O))+1] -
	   h_cue[tbl][chunk >> (19-NC_O)]);
           h_cue[tbl][chunk >> (19-NC_O)]);
    else {
      /* we strongly depend on h_cue[N_CUE-1] to point to
       * the last entry in the huffman table, so we should
       * not get here anyway. if it didn't, we'd have to
       * have another table with huffman tables lengths, and
       * it would be a mess. just in case, scream&shout.
       */ 
       */
      /*      printf(" h_cue clobbered. this is a bug. blip.\n");*/
      exit (-1);
    }
    chunk <<= 32-19;
    chunk |= 0x1ff;

    half_lag = lag >> 1;

    h_tab += half_lag;
    lag -= half_lag;

    while (lag > 1) {
      half_lag = lag >> 1;

      if (*h_tab < chunk)
	h_tab += half_lag;
        h_tab += half_lag;
      else
	h_tab -= half_lag;
        h_tab -= half_lag;

      lag -= half_lag;
    }

    len=(*h_tab>>8)&0x1f;
    if ((*h_tab>>(32-len)) != (chunk>>(32-len))) {
      if (*h_tab > chunk)
	h_tab--;
      else 
	h_tab++;
                  
        h_tab--;
      else
        h_tab++;

      len=(*h_tab>>8)&0x1f;
    }
  }
  sackbits(len);
  *x=(*h_tab>>4)&0xf;
  *y=*h_tab&0xf;
  return len;
1260
1261
1262
1263
1264
1265
1266
1267
1268


1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281


1282
1283
1284


1285
1286

1287
1288
1289
1290
1291
1292
1293






1294
1295

1296
1297

1298
1299
1300
1301
1302
1303
1304






1305
1306

1307
1308

1309
1310
1311
1312



1313
1314

1315
1316
1317
1318
1319
1320
1321
1259
1260
1261
1262
1263
1264
1265


1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278


1279
1280
1281


1282
1283
1284

1285
1286






1287
1288
1289
1290
1291
1292
1293

1294
1295

1296
1297






1298
1299
1300
1301
1302
1303
1304

1305
1306

1307
1308



1309
1310
1311
1312

1313
1314
1315
1316
1317
1318
1319
1320







-
-
+
+











-
-
+
+

-
-
+
+

-
+

-
-
-
-
-
-
+
+
+
+
+
+

-
+

-
+

-
-
-
-
-
-
+
+
+
+
+
+

-
+

-
+

-
-
-
+
+
+

-
+







  float *in = xr[ch][sb];
  float out[36];


  if(win_type == 2){
    for(p=0;p<36;p+=9) {
      out[p]   = out[p+1] = out[p+2] = out[p+3] =
	out[p+4] = out[p+5] = out[p+6] = out[p+7] =
	out[p+8] = 0.0f;
        out[p+4] = out[p+5] = out[p+6] = out[p+7] =
        out[p+8] = 0.0f;
    }

    for(ss=0;ss<18;ss+=6) {

      /*
       *  12 point IMDCT
       */

      /* Begin 12 point IDCT */

      /* Input aliasing for 12 pt IDCT*/
				      in[5+ss]+=in[4+ss];in[4+ss]+=in[3+ss];in[3+ss]+=in[2+ss];
				      in[2+ss]+=in[1+ss];in[1+ss]+=in[0+ss];
                                      in[5+ss]+=in[4+ss];in[4+ss]+=in[3+ss];in[3+ss]+=in[2+ss];
                                      in[2+ss]+=in[1+ss];in[1+ss]+=in[0+ss];

				      /* Input aliasing on odd indices (for 6 point IDCT) */
					   in[5+ss] += in[3+ss];  in[3+ss]  += in[1+ss];
                                      /* Input aliasing on odd indices (for 6 point IDCT) */
                                           in[5+ss] += in[3+ss];  in[3+ss]  += in[1+ss];

					   /* 3 point IDCT on even indices */
                                           /* 3 point IDCT on even indices */

						pp2 = in[4+ss] * 0.500000000f;
					   pp1 = in[2+ss] * 0.866025403f;
					   sum = in[0+ss] + pp2;
					   tmp[1]= in[0+ss] - in[4+ss];
					   tmp[0]= sum + pp1;
					   tmp[2]= sum - pp1;
                                                pp2 = in[4+ss] * 0.500000000f;
                                           pp1 = in[2+ss] * 0.866025403f;
                                           sum = in[0+ss] + pp2;
                                           tmp[1]= in[0+ss] - in[4+ss];
                                           tmp[0]= sum + pp1;
                                           tmp[2]= sum - pp1;

					   /* End 3 point IDCT on even indices */
                                           /* End 3 point IDCT on even indices */

					   /* 3 point IDCT on odd indices (for 6 point IDCT) */
                                           /* 3 point IDCT on odd indices (for 6 point IDCT) */

						pp2 = in[5+ss] * 0.500000000f;
					   pp1 = in[3+ss] * 0.866025403f;
					   sum = in[1+ss] + pp2;
					   tmp[4] = in[1+ss] - in[5+ss];
					   tmp[5] = sum + pp1;
					   tmp[3] = sum - pp1;
                                                pp2 = in[5+ss] * 0.500000000f;
                                           pp1 = in[3+ss] * 0.866025403f;
                                           sum = in[1+ss] + pp2;
                                           tmp[4] = in[1+ss] - in[5+ss];
                                           tmp[5] = sum + pp1;
                                           tmp[3] = sum - pp1;

					   /* End 3 point IDCT on odd indices*/
                                           /* End 3 point IDCT on odd indices*/

					   /* Twiddle factors on odd indices (for 6 point IDCT)*/
                                           /* Twiddle factors on odd indices (for 6 point IDCT)*/

						tmp[3] *= 1.931851653f;
					   tmp[4] *= 0.707106781f;
					   tmp[5] *= 0.517638090f;
                                                tmp[3] *= 1.931851653f;
                                           tmp[4] *= 0.707106781f;
                                           tmp[5] *= 0.517638090f;

					   /* Output butterflies on 2 3 point IDCT's (for 6 point IDCT)*/
                                           /* Output butterflies on 2 3 point IDCT's (for 6 point IDCT)*/

save = tmp[0];
tmp[0] += tmp[5];
tmp[5] = save - tmp[5];
save = tmp[1];
tmp[1] += tmp[4];
tmp[4] = save - tmp[4];
1564
1565
1566
1567
1568
1569
1570
1571

1572
1573
1574
1575
1576
1577
1578
1563
1564
1565
1566
1567
1568
1569

1570
1571
1572
1573
1574
1575
1576
1577







-
+







res[sb][2] =-tmp[11] * win_bt[2] + s[ch][sb][2];
res[sb][3] =-tmp[12] * win_bt[3] + s[ch][sb][3];
res[sb][4] =-tmp[13] * win_bt[4] + s[ch][sb][4];
res[sb][5] =-tmp[14] * win_bt[5] + s[ch][sb][5];
res[sb][6] =-tmp[15] * win_bt[6] + s[ch][sb][6];
res[sb][7] =-tmp[16] * win_bt[7] + s[ch][sb][7];
res[sb][8] =-tmp[17] * win_bt[8] + s[ch][sb][8];
           

res[sb][9] = tmp[17] * win_bt[9] + s[ch][sb][9];
res[sb][10]= tmp[16] * win_bt[10] + s[ch][sb][10];
res[sb][11]= tmp[15] * win_bt[11] + s[ch][sb][11];
res[sb][12]= tmp[14] * win_bt[12] + s[ch][sb][12];
res[sb][13]= tmp[13] * win_bt[13] + s[ch][sb][13];
res[sb][14]= tmp[12] * win_bt[14] + s[ch][sb][14];
res[sb][15]= tmp[11] * win_bt[15] + s[ch][sb][15];
1602
1603
1604
1605
1606
1607
1608
1609

1610
1611
1612
1613
1614
1615
1616
1601
1602
1603
1604
1605
1606
1607

1608
1609
1610
1611
1612
1613
1614
1615







-
+







}

if (sb&1) for (i=1;i<18;i+=2) res[sb][i]=-res[sb][i];
}

/* fast DCT according to Lee[84]
 * reordering according to Konstantinides[94]
 */ 
 */
void poly(mp3Info* ext, const int ch,int f)
{
float c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15;
float c16,c17,c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29,c30,c31;
float d0,d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15;
float d16,d17,d18,d19,d20,d21,d22,d23,d24,d25,d26,d27,d28,d29,d30,d31;
int start = ext->u_start[ch];
1670
1671
1672
1673
1674
1675
1676
1677

1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694

1695
1696

1697
1698

1699
1700
1701


1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721


1722
1723
1724
1725
1726
1727
1728
1669
1670
1671
1672
1673
1674
1675

1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692

1693
1694

1695
1696

1697
1698


1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718


1719
1720
1721
1722
1723
1724
1725
1726
1727







-
+
















-
+

-
+

-
+

-
-
+
+


















-
-
+
+







d10= c10+ c14; d14= (c10 - c14) * b28;
d11= c11+ c15; d15= (c11 - c15) * b20;

d16= c16+ c20; d20= (c16 - c20) *  b4;
d17= c17+ c21; d21= (c17 - c21) * b12;
d18= c18+ c22; d22= (c18 - c22) * b28;
d19= c19+ c23; d23= (c19 - c23) * b20;
        

d24= c24+ c28; d28= (c24 - c28) *  b4;
d25= c25+ c29; d29= (c25 - c29) * b12;
d26= c26+ c30; d30= (c26 - c30) * b28;
d27= c27+ c31; d31= (c27 - c31) * b20;

/* step 4: 2-wide butterflies
 */
/**/    c0 = d0 + d2 ; c2 = ( d0 - d2 ) *  b8;
c1 = d1 + d3 ; c3 = ( d1 - d3 ) * b24;
/**/    c4 = d4 + d6 ; c6 = ( d4 - d6 ) *  b8;
c5 = d5 + d7 ; c7 = ( d5 - d7 ) * b24;
/**/    c8 = d8 + d10; c10= ( d8 - d10) *  b8;
c9 = d9 + d11; c11= ( d9 - d11) * b24;
/**/    c12= d12+ d14; c14= (d12 - d14) *  b8;
c13= d13+ d15; c15= (d13 - d15) * b24;
/**/    c16= d16+ d18; c18= (d16 - d18) *  b8;
c17= d17+ d19; c19= (d17 - d19) * b24; 
c17= d17+ d19; c19= (d17 - d19) * b24;
/**/    c20= d20+ d22; c22= (d20 - d22) *  b8;
c21= d21+ d23; c23= (d21 - d23) * b24; 
c21= d21+ d23; c23= (d21 - d23) * b24;
/**/    c24= d24+ d26; c26= (d24 - d26) *  b8;
c25= d25+ d27; c27= (d25 - d27) * b24; 
c25= d25+ d27; c27= (d25 - d27) * b24;
/**/    c28= d28+ d30; c30= (d28 - d30) *  b8;
c29= d29+ d31; c31= (d29 - d31) * b24; 
 
c29= d29+ d31; c31= (d29 - d31) * b24;

/* step 5: 1-wide butterflies
 */
d0 = c0 + c1 ; d1 = ( c0 - c1 ) * b16;
d2 = c2 + c3 ; d3 = ( c2 - c3 ) * b16;
d4 = c4 + c5 ; d5 = ( c4 - c5 ) * b16;
d6 = c6 + c7 ; d7 = ( c6 - c7 ) * b16;
d8 = c8 + c9 ; d9 = ( c8 - c9 ) * b16;
d10= c10+ c11; d11= (c10 - c11) * b16;
d12= c12+ c13; d13= (c12 - c13) * b16;
d14= c14+ c15; d15= (c14 - c15) * b16;
d16= c16+ c17; d17= (c16 - c17) * b16;
d18= c18+ c19; d19= (c18 - c19) * b16;
d20= c20+ c21; d21= (c20 - c21) * b16;
d22= c22+ c23; d23= (c22 - c23) * b16;
d24= c24+ c25; d25= (c24 - c25) * b16;
d26= c26+ c27; d27= (c26 - c27) * b16;
d28= c28+ c29; d29= (c28 - c29) * b16;
d30= c30+ c31; d31= (c30 - c31) * b16;
 
/* step 6: final resolving & reordering 

/* step 6: final resolving & reordering
 * the other 32 are stored for use with the next granule
 */

u_p = (float (*)[16]) &ext->u[ch][div][0][start];

/*16*/                 u_p[0][0] =+d1 ;
u_p[31][0] = -(u_p[1][0] =+d16 +d17 +d18 +d22 -d30);
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
















1806
1807

1808
1809
1810
1811
1812
1813

1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
















1831
1832

1833
1834
1835
1836
1837
1838

1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
















1856
1857

1858
1859
1860
1861
1862
1863

1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
















1881
1882

1883
1884
1885
1886
1887
1888

1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
















1906
1907

1908
1909
1910
1911
1912
1913

1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
















1931
1932

1933
1934
1935
1936
1937
1938

1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
















1956
1957

1958
1959
1960
1961
1962
1963

1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
















1981
1982

1983
1984
1985
1986
1987
1988
1989
1990

1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
















2008
2009

2010
2011
2012
2013
2014
2015

2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
















2033
2034

2035
2036
2037
2038
2039
2040

2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
















2058
2059

2060
2061
2062
2063
2064
2065

2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
















2083
2084

2085
2086
2087
2088
2089
2090

2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
















2108
2109

2110
2111
2112
2113
2114
2115

2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
















2133
2134

2135
2136
2137
2138
2139
2140

2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
















2158
2159

2160
2161
2162
2163
2164
2165

2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
















2183
2184

2185
2186
2187
2188
2189
2190
2191

2192
2193
2194


2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
















2212
2213
2214


2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246


















2247
2248
2249
2250
2251
2252

2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
















2270
2271

2272
2273
2274
2275
2276
2277

2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
















2295
2296

2297
2298
2299
2300
2301
2302

2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
















2320
2321

2322
2323
2324
2325
2326
2327

2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
















2345
2346

2347
2348
2349
2350
2351
2352

2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
















2370
2371

2372
2373
2374
2375
2376
2377

2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
















2395
2396

2397
2398
2399
2400
2401
2402

2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
















2420
2421

2422
2423
2424
2425
2426
2427
2428
2429

2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
















2447
2448

2449
2450
2451
2452
2453
2454

2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
















2472
2473

2474
2475
2476
2477
2478
2479

2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
















2497
2498

2499
2500
2501
2502
2503
2504

2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
















2522
2523

2524
2525
2526
2527
2528
2529

2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
















2547
2548

2549
2550
2551
2552
2553
2554

2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
















2572
2573

2574
2575
2576
2577
2578
2579

2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
















2597
2598

2599
2600
2601
2602
2603
2604

2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
















2622
2623

2624
2625
2626
2627
2628
2629
2630

2631
2632
2633


2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
















2651
2652
2653


2654
2655
2656
2657
2658
2659
2660
1782
1783
1784
1785
1786
1787
1788
















1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805

1806
1807
1808
1809
1810
1811

1812
1813
















1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830

1831
1832
1833
1834
1835
1836

1837
1838
















1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855

1856
1857
1858
1859
1860
1861

1862
1863
















1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880

1881
1882
1883
1884
1885
1886

1887
1888
















1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905

1906
1907
1908
1909
1910
1911

1912
1913
















1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930

1931
1932
1933
1934
1935
1936

1937
1938
















1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955

1956
1957
1958
1959
1960
1961

1962
1963
















1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980

1981
1982
1983
1984
1985
1986
1987
1988

1989
1990
















1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007

2008
2009
2010
2011
2012
2013

2014
2015
















2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032

2033
2034
2035
2036
2037
2038

2039
2040
















2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057

2058
2059
2060
2061
2062
2063

2064
2065
















2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082

2083
2084
2085
2086
2087
2088

2089
2090
















2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107

2108
2109
2110
2111
2112
2113

2114
2115
















2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132

2133
2134
2135
2136
2137
2138

2139
2140
















2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157

2158
2159
2160
2161
2162
2163

2164
2165
















2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182

2183
2184
2185
2186
2187
2188
2189

2190
2191


2192
2193
2194
















2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211


2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227


















2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250

2251
2252
















2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269

2270
2271
2272
2273
2274
2275

2276
2277
















2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294

2295
2296
2297
2298
2299
2300

2301
2302
















2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319

2320
2321
2322
2323
2324
2325

2326
2327
















2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344

2345
2346
2347
2348
2349
2350

2351
2352
















2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369

2370
2371
2372
2373
2374
2375

2376
2377
















2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394

2395
2396
2397
2398
2399
2400

2401
2402
















2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419

2420
2421
2422
2423
2424
2425
2426
2427

2428
2429
















2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446

2447
2448
2449
2450
2451
2452

2453
2454
















2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471

2472
2473
2474
2475
2476
2477

2478
2479
















2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496

2497
2498
2499
2500
2501
2502

2503
2504
















2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521

2522
2523
2524
2525
2526
2527

2528
2529
















2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546

2547
2548
2549
2550
2551
2552

2553
2554
















2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571

2572
2573
2574
2575
2576
2577

2578
2579
















2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596

2597
2598
2599
2600
2601
2602

2603
2604
















2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621

2622
2623
2624
2625
2626
2627
2628

2629
2630


2631
2632
2633
















2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650


2651
2652
2653
2654
2655
2656
2657
2658
2659







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+







-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+






-
+

-
-
+
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
+
+














-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+







-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+





-
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+






-
+

-
-
+
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
+
+








    switch (start) {
#if !defined(MEDIUM_STEREO_CACHE) && !defined(SMALL_STEREO_CACHE)
    case 0:
      u_ptr = (float *) u_p;

      for (j=0;j<32;j++) {
	out  = *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
        out  = *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;

	stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 1:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
        out  = u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;

	stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ?-32768.0f : out;
        stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ?-32768.0f : out;
      }
      break;

    case 2:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
        out  = u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;

	stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 3:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
        out  = u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;

	stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 4:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
        out  = u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;

	stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 5:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
        out  = u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;

	stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 6:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
        out  = u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;

	stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 7:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
        out  = u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;

	stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

#endif
#if !defined(SMALL_STEREO_CACHE)
    case 8:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
        out  = u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;

	stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 9:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
        out  = u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;

	stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 10:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
        out  = u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;

	stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 11:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
        out  = u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;

	stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 12:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
        out  = u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;

	stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 13:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
        out  = u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;

	stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 14:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
        out  = u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;

	stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 15:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
        out  = u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;

	stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;
#endif
#if defined(MEDIUM_STEREO_CACHE) || defined(SMALL_STEREO_CACHE)
    default:
      {
	int i=start;
        int i=start;

	for (j=0;j<32;j++) {
	  u_ptr = u_p[j];
        for (j=0;j<32;j++) {
          u_ptr = u_p[j];

	  out  = u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
          out  = u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;

	  stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
	}
          stereo_samples[f][j][ch] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        }
      }
      break;
#endif
    }

    ext->u_start[ch] = (ext->u_start[ch]-1)&0xf;
    ext->u_div[ch] = ext->u_div[ch] ? 0 : 1;
  } else {
    switch (start) {
#if !defined(MEDIUM_MONO_CACHE) && !defined(SMALL_MONO_CACHE)
    case 0:
      u_ptr = (float *) u_p;

      for (j=0;j<32;j++) {
	out  = *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	out += *u_ptr++ * *dewindow++;
	
	mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        out  = *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;
        out += *u_ptr++ * *dewindow++;

        mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 1:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
        out  = u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;

	mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 2:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
        out  = u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;

	mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 3:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
        out  = u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;

	mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 4:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
        out  = u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;

	mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 5:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
        out  = u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;

	mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 6:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
        out  = u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;

	mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 7:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
        out  = u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;

	mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

#endif
#if !defined(SMALL_MONO_CACHE)
    case 8:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
        out  = u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;

	mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 9:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
        out  = u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;

	mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 10:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
        out  = u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;

	mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 11:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
        out  = u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;

	mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 12:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
        out  = u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;

	mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 13:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
        out  = u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;

	mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 14:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[14] * *dewindow++;
	out += u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
        out  = u_ptr[14] * *dewindow++;
        out += u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;

	mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;

    case 15:
      for (j=0;j<32;j++) {
	u_ptr = u_p[j];
        u_ptr = u_p[j];

	out  = u_ptr[15] * *dewindow++;
	out += u_ptr[0] * *dewindow++;
	out += u_ptr[1] * *dewindow++;
	out += u_ptr[2] * *dewindow++;
	out += u_ptr[3] * *dewindow++;
	out += u_ptr[4] * *dewindow++;
	out += u_ptr[5] * *dewindow++;
	out += u_ptr[6] * *dewindow++;
	out += u_ptr[7] * *dewindow++;
	out += u_ptr[8] * *dewindow++;
	out += u_ptr[9] * *dewindow++;
	out += u_ptr[10] * *dewindow++;
	out += u_ptr[11] * *dewindow++;
	out += u_ptr[12] * *dewindow++;
	out += u_ptr[13] * *dewindow++;
	out += u_ptr[14] * *dewindow++;
        out  = u_ptr[15] * *dewindow++;
        out += u_ptr[0] * *dewindow++;
        out += u_ptr[1] * *dewindow++;
        out += u_ptr[2] * *dewindow++;
        out += u_ptr[3] * *dewindow++;
        out += u_ptr[4] * *dewindow++;
        out += u_ptr[5] * *dewindow++;
        out += u_ptr[6] * *dewindow++;
        out += u_ptr[7] * *dewindow++;
        out += u_ptr[8] * *dewindow++;
        out += u_ptr[9] * *dewindow++;
        out += u_ptr[10] * *dewindow++;
        out += u_ptr[11] * *dewindow++;
        out += u_ptr[12] * *dewindow++;
        out += u_ptr[13] * *dewindow++;
        out += u_ptr[14] * *dewindow++;

	mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
      }
      break;
#endif
#if defined(MEDIUM_MONO_CACHE) || defined(SMALL_MONO_CACHE)
    default:
      {
	int i=start;
        int i=start;

	for (j=0;j<32;j++) {
	  u_ptr = u_p[j];
        for (j=0;j<32;j++) {
          u_ptr = u_p[j];

	  out  = u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
	  out += u_ptr[i++ & 0xf] * *dewindow++;
          out  = u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;
          out += u_ptr[i++ & 0xf] * *dewindow++;

	  mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
	}
          mono_samples[f][j] = out > 32767.0f ? 32767.0f : out < -32768.0f ? -32768.0f : out;
        }
      }
      break;
#endif
    }

    ext->u_start[0] = (ext->u_start[0]-1)&0xf;
    ext->u_div[0] = ext->u_div[0] ? 0 : 1;
2684
2685
2686
2687
2688
2689
2690
2691

2692
2693
2694
2695
2696
2697
2698
2683
2684
2685
2686
2687
2688
2689

2690
2691
2692
2693
2694
2695
2696
2697







-
+







  int gr,ch,sb,i,tmp;
  int mean_frame_size,bitrate,fs,hsize,ssize;
  int cnt = ext->cnt;
  char *rest = (char *) ext->rest;

  /* we need these later, hsize is the size of header+side_info */

  if (header->ID) 
  if (header->ID)
    if (header->mode==3) {
      nch=1;
      hsize=21;
    } else {
      nch=2;
      hsize=36;
    }
2720
2721
2722
2723
2724
2725
2726
2727

2728
2729
2730
2731
2732
2733
2734
2719
2720
2721
2722
2723
2724
2725

2726
2727
2728
2729
2730
2731
2732
2733







-
+







  fs=t_sampling_frequency[header->ID][header->sampling_frequency];
  if (header->ID) mean_frame_size=144000*bitrate/fs;
  else mean_frame_size=72000*bitrate/fs;

  /* check if mdb is too big for the first few frames. this means that
   * a part of the stream could be missing. We must still fill the buffer
   */
  if (info.main_data_begin > append) 
  if (info.main_data_begin > append)
    if (cnt*mean_frame_size < 960) {
      /*printf(" frame %d discarded, incomplete main_data\n",cnt);*/
      fillbfr(mean_frame_size + header->padding_bit - hsize);
      return 0;
    }


2745
2746
2747
2748
2749
2750
2751
2752

2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771

2772
2773
2774
2775
2776
2777
2778
2779

2780
2781
2782
2783
2784
2785
2786

2787
2788
2789

2790
2791
2792
2793
2794
2795

2796
2797
2798
2799
2800
2801
2802
2803
2804
2805






2806
2807
2808
2809
2810

2811
2812
2813
2814
2815
2816
2817
2818
2819



2820
2821
2822
2823
2824
2825
2826
2827
2828



2829
2830
2831

2832
2833
2834
2835

2836
2837
2838
2839
2840
2841
2842
2744
2745
2746
2747
2748
2749
2750

2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769

2770
2771
2772
2773
2774
2775
2776
2777

2778
2779
2780
2781
2782
2783
2784

2785
2786
2787

2788
2789
2790
2791
2792
2793

2794
2795
2796
2797
2798






2799
2800
2801
2802
2803
2804
2805
2806
2807
2808

2809
2810
2811
2812
2813
2814
2815



2816
2817
2818
2819
2820
2821
2822
2823
2824



2825
2826
2827
2828
2829

2830
2831
2832
2833

2834
2835
2836
2837
2838
2839
2840
2841







-
+


















-
+







-
+






-
+


-
+





-
+




-
-
-
-
-
-
+
+
+
+
+
+




-
+






-
-
-
+
+
+






-
-
-
+
+
+


-
+



-
+








  t_l=&t_b8_l[header->ID][header->sampling_frequency][0];
  t_s=&t_b8_s[header->ID][header->sampling_frequency][0];

  /* debug/dump stuff */
  /*  show_header(header,bitrate,fs,mean_frame_size,0);*/
  /*if (A_DUMP_BINARY) dump((int *)info.part2_3_length);*/
  

  /* decode the scalefactors and huffman data
   * this part needs to be enhanced for error robustness
   */
  for (gr=0;gr < ((header->ID) ? 2 : 1);gr++) {
    for (ch=0;ch<nch;ch++) {
      /*       show_side_info(&info,gr,ch,0);*/ /* this is for debug/dump */
      ssize=decode_scalefactors(&info,header,gr,ch);
      decode_huffman_data(&info,gr,ch,ssize);
    }

    /* requantization, stereo processing, reordering(shortbl) */
    if (header->mode!=1 || (header->mode==1 && header->mode_extension==0))
      for (ch=0;ch<nch;ch++) requantize_mono(gr,ch,&info,header);
    else requantize_ms(gr,&info,header);

    /* antialiasing butterflies */
    for (ch=0;ch<nch;ch++) {
      if(!(info.window_switching_flag[gr][ch] && info.block_type[gr][ch]==2))
	alias_reduction(ch);
        alias_reduction(ch);
    }

    /* just which window? */
    for (ch=0;ch<nch;ch++) {
      int win_type; /* same as in the standard, long=0, start=1 ,.... */

      if (info.window_switching_flag[gr][ch] && info.block_type[gr][ch]==2 && info.mixed_block_flag[gr][ch])
	win_type=0;
        win_type=0;
      else if (!info.window_switching_flag[gr][ch]) win_type=0;
      else win_type=info.block_type[gr][ch];

      /* imdct ...  */

      for (sb=0;sb<2;sb++)
	imdct(win_type,sb,ch);
        imdct(win_type,sb,ch);

      if (info.window_switching_flag[gr][ch] && info.block_type[gr][ch]==2 && info.mixed_block_flag[gr][ch])
	win_type=2;
        win_type=2;

      /* no_of_imdcts tells us how many subbands from the top are all zero
       * it is set by the requantize functions in misc2.c
       */
      for (sb=2;sb<no_of_imdcts[ch];sb++)
	imdct(win_type,sb,ch);
        imdct(win_type,sb,ch);

      /* clear s[][][] first so we don't totally blow the cache */

      tmp = sb;
      for (;sb<32;sb++) 
	for (i=0;i<18;i++) {
	  res[sb][i]=s[ch][sb][i];
	  s[ch][sb][i]=0.0f;
	}
	
      for (;sb<32;sb++)
        for (i=0;i<18;i++) {
          res[sb][i]=s[ch][sb][i];
          s[ch][sb][i]=0.0f;
        }

      /* polyphase filterbank
       */
      /* if (nch == 2) this was a bug, tomislav */
      for (i=0;i<18;i++)
	poly(ext, ch, i);
        poly(ext, ch, i);
    }
    if (nch == 2) {
      int l = min(18*32*2*4, len - ext->ind);
      memcpy(&mm[ext->ind], stereo_samples, l);
      ext->ind += l;
      if (l < 18*32*2*4) {
	memcpy(&rest[ext->restlen],
	       &((char *)stereo_samples)[l], 18*32*2*4 - l);
	ext->restlen += (18*32*2*4 - l);
        memcpy(&rest[ext->restlen],
               &((char *)stereo_samples)[l], 18*32*2*4 - l);
        ext->restlen += (18*32*2*4 - l);
      }
    } else {
      int l = min(18*32*4, len - ext->ind);
      memcpy(&mm[ext->ind], mono_samples, l);
      ext->ind += l;
      if (l < 18*32*4) {
	memcpy(&rest[ext->restlen],
	       &((char *)mono_samples)[l], 18*32*4 - l);
	ext->restlen += (18*32*4 - l);
        memcpy(&rest[ext->restlen],
               &((char *)mono_samples)[l], 18*32*4 - l);
        ext->restlen += (18*32*4 - l);
      }
    }
  }    /*  for (gr... */ 
  }    /*  for (gr... */

  return 0;

} 
}

static int
processHeader(Sound *s, struct AUDIO_HEADER *header, int cnt)
{
  int g;
  mp3Info *Si = (mp3Info *)s->extHead;

2850
2851
2852
2853
2854
2855
2856
2857

2858
2859
2860
2861
2862

2863
2864
2865
2866
2867
2868
2869
2849
2850
2851
2852
2853
2854
2855

2856
2857
2858
2859
2860

2861
2862
2863
2864
2865
2866
2867
2868







-
+




-
+







  }
  Si->gotHeader = 0;

  while ((g=gethdr(header))!=0) {
    if (_fillbfr(4) <= 0) return(1);
  }
  if (header->protection_bit==0) getcrc();
  

  return(0);
}

#define MAXFRAMESIZE 2106  /* frame size starting at header */
#define MAXSCANDEPTH 60000 /* How deep to scan into file to find first frame, assume bad after this */
#define MAXSCANDEPTH 65536 /* How deep to scan into file to find first frame, assume bad after this */
/* Define a mask such that a seek frame has to match the original frame
   some data changes from frame to frame so ignore those changes
   at a minimum the
   frame sync
   ID/Layer/Protection Bit
*/
/*#define HMASK 0xfffffddf*/
2909
2910
2911
2912
2913
2914
2915
2916
2917


2918
2919
2920
2921
2922
2923
2924
2925

2926
2927
2928

2929
2930

2931
2932

2933
2934

2935
2936
2937

2938
2939
2940
2941
2942



2943
2944
2945
2946
2947
2948
2949
2950
2951





2952
2953
2954
2955
2956

2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971





















2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982




















2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010



























3011
3012
3013
3014




3015

3016

3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038




































3039
3040
3041

3042
3043
3044
3045
3046
3047
3048
3049



3050
3051
3052
3053
3054
3055
3056
3057
3058
3059










3060
3061
3062
3063
3064
3065
3066








3067
3068
3069
3070
3071
3072














3073
3074

3075
3076
3077
3078
3079






3080
3081
3082
3083
3084













3085
3086
3087
3088






3089
3090
3091


3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130







































3131
3132
3133
3134




3135

3136

3137
3138
3139
3140







3141
3142

3143
3144

3145
3146
3147


3148
3149

3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164















3165
3166


3167
3168

3169
3170

3171
3172
3173
3174
3175
3176
3177
3178

3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192

3193
3194
3195
3196
3197
3198
3199
2908
2909
2910
2911
2912
2913
2914


2915
2916
2917
2918
2919
2920
2921
2922
2923

2924
2925
2926

2927
2928

2929
2930

2931
2932

2933
2934
2935

2936
2937
2938



2939
2940
2941
2942
2943
2944
2945





2946
2947
2948
2949
2950
2951
2952
2953
2954

2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996






2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017



























3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054

3055
3056
3057




















3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093

3094

3095
3096
3097
3098
3099
3100



3101
3102
3103
3104









3105
3106
3107
3108
3109
3110
3111
3112
3113
3114







3115
3116
3117
3118
3119
3120
3121
3122






3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136


3137





3138
3139
3140
3141
3142
3143





3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156




3157
3158
3159
3160
3161
3162



3163
3164
3165






































3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204




3205
3206
3207
3208
3209
3210

3211




3212
3213
3214
3215
3216
3217
3218


3219
3220

3221



3222
3223
3224

3225















3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241

3242
3243
3244

3245
3246

3247
3248
3249
3250
3251
3252
3253
3254

3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268

3269
3270
3271
3272
3273
3274
3275
3276







-
-
+
+







-
+


-
+

-
+

-
+

-
+


-
+


-
-
-
+
+
+




-
-
-
-
-
+
+
+
+
+




-
+















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+





-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+




+
+
+
+

+
-
+


-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-

-
+





-
-
-
+
+
+

-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+

+
-
+
-
-
-
-
+
+
+
+
+
+
+
-
-
+

-
+
-
-
-
+
+

-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+
+

-
+

-
+







-
+













-
+







    return(NULL);
  }

  depth = min(MAXSCANDEPTH,len);
  while (offset <= depth - 4) {
    /* Validate frame sync and other data to make sure this is a good header */
    if ((buf[offset]   & 0xff) == 0xff && (buf[offset+1] & 0xe0) == 0xe0 &&
	(buf[offset+2] & 0x0c) != 0x0c && (buf[offset+2] & 0xf0) != 0x00 &&
	(buf[offset+2] & 0xf0) != 0xf0 && (buf[offset+1] & 0x06) != 0x00) {
        (buf[offset+2] & 0x0c) != 0x0c && (buf[offset+2] & 0xf0) != 0x00 &&
        (buf[offset+2] & 0xf0) != 0xf0 && (buf[offset+1] & 0x06) != 0x00) {
      int layer = (buf[offset+1] & 0x06) >> 1;
      int br_index = (buf[offset+2] & 0xf0) >> 4;
      int sr_index = (buf[offset+2] & 0x0c) >> 2;
      int id = (buf[offset+1] & 0x08) >> 3;
      int bitrate = t_bitrate[id][3 - layer][br_index];
      int fs = t_sampling_frequency[id][sr_index];
      int mean_frame_size;
      

      if (id) mean_frame_size = 144000 * bitrate / fs;
      else mean_frame_size = 72000 * bitrate / fs;
      

      if (mean_frame_size > MAXFRAMESIZE) {
	mean_frame_size = MAXFRAMESIZE;
        mean_frame_size = MAXFRAMESIZE;
      }
      

      if (offset == 0 || offset == 72) {
	return(MP3_STRING);
        return(MP3_STRING);
      }
      if (offset + mean_frame_size + 4 >= len && len > 1000) {
	return(NULL);
        return(NULL);
      }

      /* A valid MP3 should have a header at the next location, 
	 and they should nearly match (sync + ID/Layer/Pro bit 
	 just to make sure we need two additional matches.
      /* A valid MP3 should have a header at the next location,
         and they should nearly match (sync + ID/Layer/Pro bit
         just to make sure we need two additional matches.
      */
      p = &buf[offset];
      q = p + mean_frame_size;
      if (p[0] == q[0] && p[1] == q[1]) {
	matches++;
	/* Require at least three frames have this kind of match */
	if (matches > 2) {
	  return(MP3_STRING);
	}
        matches++;
        /* Require at least three frames have this kind of match */
        if (matches > 2) {
          return(MP3_STRING);
        }
      }
    }
    offset++;
  }
  if (offset < 1000) {
  if (offset < 1001) {
    return(QUE_STRING);
  } else {
    return(NULL);
  }
}

static int initDone = 0;

static void
InitMP3()
{
  premultiply();
  imdct_init();
}

extern struct Snack_FileFormat *snackFileFormats;

#define SNACK_MP3_INT 18
static int ExtractI4(unsigned char *buf)
{
   int x;
   /*  big endian extract  */
   x = buf[0];
   x <<= 8;
   x |= buf[1];
   x <<= 8;
   x |= buf[2];
   x <<= 8;
   x |= buf[3];
   return x;
}
#define FRAMES_FLAG     0x0001
#define BYTES_FLAG      0x0002
#define TOC_FLAG        0x0004
#define VBR_SCALE_FLAG  0x0008

int
GetMP3Header(Sound *S, Tcl_Interp *interp, Tcl_Channel ch, Tcl_Obj *obj,
	     char *buf)
{
  int offset = 0, okHeader = 0, i, j;
  int mean_frame_size = 0, bitrate, fs;
  int layer, prot, br_index, sr_index, pad, mode, totalFrames;
  int passes = 0;
  mp3Info *Si = (mp3Info *)S->extHead;
  
  if (S->debug > 2) Snack_WriteLog("    Enter GetMP3Header\n");
   int mean_frame_size = 0, bitrate = 0, fs, ID3Extra = 0;
   int layer, prot, br_index, sr_index, pad, mode, totalFrames=0;
   int passes = 0;
   int head_flags;
   int xFrames=0, xBytes=0, xAvgBitrate=0, xAvgFrameSize=0 ;
   mp3Info *Si = (mp3Info *)S->extHead;

   if (S->debug > 2) Snack_WriteLog("    Enter GetMP3Header\n");

   if (S->extHead != NULL && S->extHeadType != SNACK_MP3_INT) {
      Snack_FileFormat *ff;

      for (ff = snackFileFormats; ff != NULL; ff = ff->nextPtr) {
         if (strcmp(S->fileType, ff->name) == 0) {
            if (ff->freeHeaderProc != NULL) {
               (ff->freeHeaderProc)(S);
            }
         }
      }
   }

  if (Si == NULL) {
    Si = (mp3Info *) ckalloc(sizeof(mp3Info));
    for (i = 0; i < 32; i++) {
      for (j = 0; j < 16; j++) {
	Si->u[0][0][i][j] = 0.0f;
	Si->u[0][1][i][j] = 0.0f;
	Si->u[1][0][i][j] = 0.0f;
	Si->u[1][1][i][j] = 0.0f;
      }
    }
    for (i = 0; i < 32; i++) {
      for (j = 0; j < 18; j++) {
	s[0][i][j] = 0.0f;
	s[1][i][j] = 0.0f;
      }
    }
    Si->u_start[0] = 0;
    Si->u_start[1] = 0;
    Si->u_div[0] = 0;
    Si->u_div[1] = 0;
    Si->cnt = 0;
    
    if (!initDone) {
      InitMP3();
      initDone = 1;
    } 
  }
   if (Si == NULL) {
      Si = (mp3Info *) ckalloc(sizeof(mp3Info));
      for (i = 0; i < 32; i++) {
         for (j = 0; j < 16; j++) {
            Si->u[0][0][i][j] = 0.0f;
            Si->u[0][1][i][j] = 0.0f;
            Si->u[1][0][i][j] = 0.0f;
            Si->u[1][1][i][j] = 0.0f;
         }
      }
      for (i = 0; i < 32; i++) {
         for (j = 0; j < 18; j++) {
            s[0][i][j] = 0.0f;
            s[1][i][j] = 0.0f;
         }
      }
      Si->u_start[0] = 0;
      Si->u_start[1] = 0;
      Si->u_div[0] = 0;
      Si->u_div[1] = 0;
      Si->cnt = 0;

      if (!initDone) {
         InitMP3();
         initDone = 1;
      }
   }
  /**
   * TFW: If any ID3V2 info is to be got, it can be read here
   * Insert code as needed.
   * See: http://www.id3.org/id3v2-00.txt for more details.
   * TFW Potential problem: if the buffer length actually passed in
   * is less than MAXSCANDEPTH the a crash may occur here. It
   * should normally be larger but on a very small file it won't
   * be.
   */
   S->length = -1;
  if (strncmp("ID3", buf, strlen("ID3")) == 0) {
   if (strncmp("ID3", buf, strlen("ID3")) == 0) {
    /* ID3 size uses 28 packed bits, or 7 LSBs of words 6-9 */
    /* The extra 10 bytes account for this header length)*/
    long idOffset = (int )((long)(buf[6]&0x7F)*2097152l
			   + (long)(buf[7]&0x7F)*16384l
			   + (long)(buf[8]&0x7F)*128l
			   + (long)buf[9] + 10);
    offset = idOffset;
    /* Don't check for extended header yet */
    if (offset > MAXSCANDEPTH) {
      if (S->debug > 0) Snack_WriteLogInt("ID3 Tag is too big", offset);
      Tcl_AppendResult(interp, "ID3 Tag is too big", NULL);
      return TCL_ERROR;
    }
  }
  else if (strncasecmp("RIFF", buf, strlen("RIFF")) == 0) {
    if (buf[20] == 0x55) {
      offset = 72;
      if (S->storeType == SOUND_IN_CHANNEL) {
	Tcl_Read(ch, &buf[S->firstNRead], 76-S->firstNRead);
      }
    }
  }
      long idOffset = (int )((long)(buf[6]&0x7F)*2097152l
                             + (long)(buf[7]&0x7F)*16384l
                             + (long)(buf[8]&0x7F)*128l
                             + (long)buf[9] + 10);
      /* Attempt to read beyond the ID3 offset if it is too large */
      if (idOffset > MAXSCANDEPTH) {

         if (Tcl_Seek(ch, idOffset, SEEK_SET) > 0) {
            if (Tcl_Read(ch, &buf[0], MAXSCANDEPTH) > 0) {
               /* local buffer is now at end of ID3 tag */
               offset = 0;
               ID3Extra = idOffset;
            } else {
               if (S->debug > 0) Snack_WriteLogInt("ID3 size is in error is too big", offset);
                  Tcl_AppendResult(interp, "ID3 size is in error is too big", NULL);
                  return TCL_ERROR;
               }

         } else {
            if (S->debug > 0) Snack_WriteLogInt("ID3 Tag is bigger than file size", offset);
            Tcl_AppendResult(interp, "ID3 Tag is bigger than file size", NULL);
            return TCL_ERROR;
         }

      } else {
         offset = idOffset;
      }
   }
   else if (strncasecmp("RIFF", buf, strlen("RIFF")) == 0) {
      if (buf[20] == 0x55) {
         offset = 72;
         if (S->storeType == SOUND_IN_CHANNEL) {
            Tcl_Read(ch, &buf[S->firstNRead], 76-S->firstNRead);
         }
      }
   }
  S->length = -1;
  /* Continue to scan until a satisfactory frame is found */
  do {
   do {
    /* Valid Frame sync
       Bit Rate not 0000 or 1111 (which are invalid)
       Layer 00 (reserved)
       Sample Rate 11 (reserved)
    */
    if ((buf[offset]   & 0xff) == 0xff && (buf[offset+1] & 0xe0) == 0xe0 &&
	(buf[offset+2] & 0x0c) != 0x0c && (buf[offset+2] & 0xf0) != 0x00 &&
	(buf[offset+2] & 0xf0) != 0xf0 && (buf[offset+1] & 0x06) != 0x00) {
      if ((buf[offset]   & 0xff) == 0xff && (buf[offset+1] & 0xe0) == 0xe0 &&
          (buf[offset+2] & 0x0c) != 0x0c && (buf[offset+2] & 0xf0) != 0x00 &&
          (buf[offset+2] & 0xf0) != 0xf0 && (buf[offset+1] & 0x06) != 0x00) {
      /* Have a good frame sync and the header data passed the initial checks */
      char *p = &buf[offset], *q = NULL;
      
      if (((buf[offset + 3] & 0xc0) >> 6) != 3) {
	S->nchannels = 2;
      } else {
	S->nchannels = 1;
      }
      S->encoding = LIN16;
      S->sampsize = 2;
	char *p = &buf[offset], *q = NULL;
	unsigned char *xBuf = (unsigned char *)p;

         if (((buf[offset + 3] & 0xc0) >> 6) != 3) {
            S->nchannels = 2;
         } else {
            S->nchannels = 1;
         }
         S->encoding = LIN16;
         S->sampsize = 2;
      S->samprate = t_sampling_frequency[(buf[offset + 1] & 0x08)>>3][(buf[offset + 2] & 0x0c)>>2];
      
      Si->id = (buf[offset+1] & 0x08) >> 3;
      layer = (buf[offset+1] & 0x06) >> 1;
      prot = (buf[offset+1] & 0x01);
      
      br_index = (buf[offset+2] & 0xf0) >> 4;

         Si->id = (buf[offset+1] & 0x08) >> 3;
         sr_index = (buf[offset+2] & 0x0c) >> 2;
         S->samprate = t_sampling_frequency[Si->id][sr_index];
         layer = (buf[offset+1] & 0x06) >> 1;
         prot = (buf[offset+1] & 0x01);

         br_index = (buf[offset+2] & 0xf0) >> 4;
      sr_index = (buf[offset+2] & 0x0c) >> 2;
      pad = (buf[offset+2] & 0x02) >> 1;
      mode = (buf[offset+3] & 0xc0) >> 6;
      /* hsize not referenced
	 if (Si->id) 
	 if (mode==3) {
         pad = (buf[offset+2] & 0x02) >> 1;
         mode = (buf[offset+3] & 0xc0) >> 6;
	 
         bitrate = t_bitrate[Si->id][3 - layer][br_index];
         fs = t_sampling_frequency[Si->id][sr_index];
         /* Xing VBR Check
          * If a Xing VBR header exists, then use the info from there
          * otherwise the length and average bitrate estimate will
          * be incorrect.
          *
          * First, determine offset of header into Aux section
          */
         if ( Si->id ) {                         /* mpeg1 */
            xBuf += 4 + (mode != 3 ? 32 : 17);
	 hsize=21;
	 } else {
         } else {                                /* mpeg */
	 hsize=36;
	 }
	 else
	 if (mode==3) {
	 hsize=13;
            xBuf += 4 + (mode != 3 ? 17 : 9);
         }

         if (strncmp("Xing",xBuf,4)==0) {
         /* We have a Xing VBR header */
            xBuf+=4;
	 } else {
	 hsize=21;
	 }
	 
	 if (prot == 0) hsize += 2;
            head_flags = ExtractI4(xBuf);
            xBuf+=4;
            if ( head_flags & FRAMES_FLAG ) {
	      xFrames   = ExtractI4(xBuf);  /* Number of frames in file */
	      xBuf+=4;
            }
            if ( head_flags & BYTES_FLAG ) {
	      xBytes = ExtractI4(xBuf);    /* File size (at encoding) */
	      xBuf+=4;
            }
            /* Enough info to compute average VBR bitrate and framesize*/
            if ( xFrames > 0 && xBytes > 0 && (head_flags & (BYTES_FLAG | FRAMES_FLAG))) {
               xAvgFrameSize =  xBytes/xFrames;
      */
      
      bitrate = t_bitrate[Si->id][3 - layer][br_index];
      fs = t_sampling_frequency[Si->id][sr_index];
               xAvgBitrate =  (xAvgFrameSize*fs)/(Si->id ? 144000:72000);   /* Layer 1 */
            }
         }

      /* End XING stuff */

      if (Si->id) mean_frame_size = 144000*bitrate / fs;
      else mean_frame_size = 72000 * bitrate / fs;
      
         mean_frame_size = (bitrate * (Si->id ? 144000:72000) / fs);   /* This frame size */

      /* Max should be 2926 */
      
      if (mean_frame_size > MAXFRAMESIZE) {
	mean_frame_size = MAXFRAMESIZE;
      }
      
      /* TFW: note to self
	 If we didn't find a header where we first expected it
	 then the next valid one must match the following on.
      */
      if (passes > 0) {
	q = p + mean_frame_size;
	/* Verify this frame and next frame headers match */
	if (p[0] == q[0] && p[1] == q[1] && (p[2] & 0xfd) == (q[2]& 0xfd)
	    && (p[3] & 0xdf) == (q[3] & 0xdf)) {
	  okHeader = 1;
	} else {
	  offset++;
	}
      } else {
	okHeader = 1;
      }
    } else {
      offset++;
    }
    if (offset > MAXSCANDEPTH) {
      if (S->debug > 0) Snack_WriteLogInt("Could not find MP3 header", offset);
      Tcl_AppendResult(interp, "Could not find MP3 header", NULL);
      return TCL_ERROR;
    }
    passes++;
  } while (okHeader == 0);
  
  if (S->debug > 0) Snack_WriteLogInt("Found MP3 header at offset", offset);
  Si->bytesPerFrame = mean_frame_size;
  
  if (ch != NULL) {
    if (Tcl_Seek(ch, 0, SEEK_END) > 0) {
      totalFrames = (Tcl_Tell(ch) - offset) / Si->bytesPerFrame;

         if (mean_frame_size > MAXFRAMESIZE) {
            mean_frame_size = MAXFRAMESIZE;
         }

         /*
            If we didn't find a header where we first expected it
            then the next valid one must match the following on.
         */
         if (passes > 0) {
            q = p + mean_frame_size;
            /* Verify this frame and next frame headers match */
            if (p[0] == q[0] && p[1] == q[1] && (p[2] & 0xfd) == (q[2]& 0xfd)
                && (p[3] & 0xdf) == (q[3] & 0xdf)) {
               okHeader = 1;
            } else {
               offset++;
            }
         } else {
            okHeader = 1;
         }
      } else {
         offset++;
      }
      if (offset > MAXSCANDEPTH) {
         if (S->debug > 0) Snack_WriteLogInt("Could not find MP3 header", offset);
         Tcl_AppendResult(interp, "Could not find MP3 header", NULL);
         return TCL_ERROR;
      }
      passes++;
   } while (okHeader == 0);

   if (S->debug > 0) Snack_WriteLogInt("Found MP3 header at offset", offset);
   Si->bytesPerFrame = xAvgFrameSize ? xAvgFrameSize : mean_frame_size;
   /* Compute length */
   if (ch != NULL) {
      if (xFrames == 0) {
         if (Tcl_Seek(ch, 0, SEEK_END) > 0) {
            totalFrames = (Tcl_Tell(ch) - (offset + ID3Extra)) / Si->bytesPerFrame;
      if (Si->id) {
	S->length = totalFrames * 18 * 32 * 2;
      } else {
	S->length = totalFrames * 18 * 32;
         }
      }
      else {
         totalFrames = xFrames;
      }
      S->length = (totalFrames * 18 * 32) * (Si->id ? 2:1);
    }
   }
  }
  if (obj != NULL) {
    if (useOldObjAPI) {
      totalFrames = (obj->length - offset) / 
   if (obj != NULL) {
      if (xFrames > 0) {
         totalFrames = xFrames;
      }
      else {
         if (useOldObjAPI) {
            totalFrames = (obj->length - (offset + ID3Extra)) / Si->bytesPerFrame;
	Si->bytesPerFrame;
    } else {
         } else {
#ifdef TCL_81_API
      int length = 0;
            int length = 0;
      
      Tcl_GetByteArrayFromObj(obj, &length);
      totalFrames = (length - offset) / Si->bytesPerFrame;
            Tcl_GetByteArrayFromObj(obj, &length);
            totalFrames = (length - (offset + ID3Extra)) / Si->bytesPerFrame;
#endif
    }
         }
    if (Si->id) {
      S->length = totalFrames * 18 * 32 * 2;
    } else {
      S->length = totalFrames * 18 * 32;
    }
  }
  
  S->headSize = offset;
  S->swap = 0;
  Si->bufind = offset;
  Si->restlen = 0;
  Si->gotHeader = 1;
  Si->append = 0;
  Si->data = 0;
  memcpy((char *)&Si->headerInt, &buf[offset], 4);
      }
      S->length = (totalFrames * 18 * 32) * (Si->id ? 2:1);
   }

   S->headSize = offset + ID3Extra;
   S->swap = 0;
   Si->bufind = offset + ID3Extra;
   Si->restlen = 0;
   Si->gotHeader = 1;
   Si->append = 0;
   Si->data = 0;
  /* If Xing header, then use an average bitrate, otherwise use this frames bitrate */
   Si->bitrate = 1000 * (xAvgBitrate ? xAvgBitrate : bitrate);

   memcpy((char *)&Si->headerInt, &buf[offset], 4);

  S->extHead = (char *) Si;
   S->extHead = (char *) Si;
   S->extHeadType = SNACK_MP3_INT;

  if (S->debug > 2) Snack_WriteLogInt("    Exit GetMP3Header", S->length);
   if (S->debug > 2) Snack_WriteLogInt("    Exit GetMP3Header", S->length);

  return TCL_OK;
   return TCL_OK;
}

#define HMASK 0xfffffddf

int
SeekMP3File(Sound *S, Tcl_Interp *interp, Tcl_Channel ch, int pos)
{
  int filepos, i, j, depth=0;
  int seekpos, filepos, i, j, depth=0;
  unsigned char tmp[4];
  unsigned int hInt = 0;
  unsigned int hmask, smask;
  mp3Info *Si = (mp3Info *)S->extHead;
  if (S->swap) {
    /* Big endian, some unixs, 68K, PPC ... */
    hmask = beHMASK;
    smask = beSMASK;
  } else {
    /* Little endian, x86, VAX */
    hmask = leHMASK;
    smask = leSMASK;
  }
  

  if (S->debug > 2) Snack_WriteLogInt("    Enter SeekMP3File", pos);

  Si->bufind = S->headSize;
  Si->restlen = 0;
  Si->append = 0;
  Si->cnt = 0;
  Si->data = 0;
3214
3215
3216
3217
3218
3219
3220
3221
3222


3223
3224

3225
3226

3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237


3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248









3249
3250
3251



3252
3253
3254


3255
3256
3257
3258
3259
3260
3261
3262
3263

3264
3265
3266
3267
3268
3269
3270
3291
3292
3293
3294
3295
3296
3297


3298
3299
3300

3301
3302

3303
3304
3305
3306
3307
3308
3309
3310
3311
3312


3313
3314
3315
3316









3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332


3333
3334
3335
3336
3337
3338
3339
3340
3341
3342

3343
3344
3345
3346
3347
3348
3349
3350







-
-
+
+

-
+

-
+









-
-
+
+


-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+



+
+
+

-
-
+
+








-
+







      s[0][i][j] = 0.0f;
      s[1][i][j] = 0.0f;
    }
  }

  /* Get approximate position */
  /* TFW Note to self: ID3 Tag is accounted for in headSize */
 
  pos = S->headSize + pos * S->sampsize * S->nchannels;

  seekpos =  pos * S->sampsize * S->nchannels;
  if (Si->id) {
    filepos = (Si->bytesPerFrame * (pos / (18 * 32 * 2 * 2 * 2)))&0xfffffffc;
    filepos = (S->headSize + (Si->bytesPerFrame * (seekpos / (18 * 32 * 2 * 2 * 2))))&0xfffffffc;
  } else {
    filepos = (Si->bytesPerFrame * (pos / (18 * 32 * 2)))&0xfffffffc;
    filepos = (S->headSize + (Si->bytesPerFrame * (seekpos / (18 * 32 * 2))))&0xfffffffc;
  }

  /* Sync up to next frame */
  hInt = Si->headerInt;
  if (ch != NULL) {
    int res;
    while (filepos == Tcl_Seek(ch, filepos, SEEK_SET)) {
      res = Tcl_Read(ch, (char *) tmp, 4);
      if (res <= 0) {
	if (S->debug > 0) Snack_WriteLogInt("    Seek beyond EOF", filepos);
	return((pos - S->headSize) / (S->sampsize * S->nchannels));
        if (S->debug > 0) Snack_WriteLogInt("    Seek beyond EOF", filepos);
        return(res); /* Denote seek beyond eof */
      }
      if ((hInt & smask) == ((((unsigned int *)tmp)[0]) & smask)) {
	/* we have a sync, not make sure the layer info matches */
	if ((hInt & hmask) == ((((unsigned int *)tmp)[0]) & hmask)) {
	  memcpy((char *)&Si->headerInt, tmp, 4);
	  Si->gotHeader = 1;
	  if (S->debug > 2) Snack_WriteLogInt("    Seek done after", depth);
	  break;
	} else {
	  depth++;      /* debugging */
	}
        /* we have a sync, not make sure the layer info matches */
        if ((hInt & hmask) == ((((unsigned int *)tmp)[0]) & hmask)) {
          memcpy((char *)&Si->headerInt, tmp, 4);
          Si->gotHeader = 1;
          if (S->debug > 2) Snack_WriteLogInt("    Seek done after", depth);
          return (pos);
        } else {
          depth++;      /* debugging */
        }
      }
      filepos++;
    }
    /* If we got here, we went past the eof */
    if (S->debug > 0) Snack_WriteLogInt("    Seek beyond EOF", filepos);
    pos = -1;
  }
  
  pos = (pos - S->headSize) / (S->sampsize * S->nchannels);

  /*  pos = (pos - S->headSize) / (S->sampsize * S->nchannels);*/

  if (S->debug > 2) Snack_WriteLogInt("    Exit SeekMP3File", pos);

  return(pos);
}

int
ReadMP3Samples(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, char *ibuf,
	       float *obuf, int len)
               float *obuf, int len)
{
  struct AUDIO_HEADER header;
  int last = -1;
  char *rest = (char *)((mp3Info *)s->extHead)->rest;
  mp3Info *Si = (mp3Info *)s->extHead;

  if (s->debug > 2) Snack_WriteLogInt("    Enter ReadMP3Samples", len);
3293
3294
3295
3296
3297
3298
3299
3300

3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3373
3374
3375
3376
3377
3378
3379

3380
3381
3382

3383
3384
3385
3386
3387
3388
3389







-
+


-







  }
  if (Si->cnt == 0) {
    Si->gotHeader = 1;
  }
  for (;; Si->cnt++) {
    if (Si->ind >= len) break;
    if (Si->ind == last &&
	Si->ind > 0) break;    
        Si->ind > 0) break;
    last = Si->ind;
    if (processHeader(s, &header, Si->cnt)) break;
    /*printf("AAAA %d\n", bufind);*/
    if (layer3_frame((mp3Info *)s->extHead, &header, len)) break;
  }

  Si->bufind = bufind;
  Si->append = append;
  Si->data = data;

3328
3329
3330
3331
3332
3333
3334












3335
3336
3337

3338
3339
3340
3341
3342
3343
3344
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436







+
+
+
+
+
+
+
+
+
+
+
+



+







int
OpenMP3File(Sound *S, Tcl_Interp *interp, Tcl_Channel *ch, char *mode)
{
  int i, j;
  mp3Info *Si = NULL;

  if (S->debug > 2) Snack_WriteLog("    Enter OpenMP3File\n");

  if (S->extHead != NULL && S->extHeadType != SNACK_MP3_INT) {
    Snack_FileFormat *ff;

    for (ff = snackFileFormats; ff != NULL; ff = ff->nextPtr) {
      if (strcmp(S->fileType, ff->name) == 0) {
        if (ff->freeHeaderProc != NULL) {
          (ff->freeHeaderProc)(S);
        }
      }
    }
  }

  if (S->extHead == NULL) {
    S->extHead = (char *) ckalloc(sizeof(mp3Info));
    S->extHeadType = SNACK_MP3_INT;
  }
  Si = (mp3Info *)S->extHead;
  for (i = 0; i < 32; i++) {
    for (j = 0; j < 16; j++) {
      Si->u[0][0][i][j] = 0.0f;
      Si->u[0][1][i][j] = 0.0f;
      Si->u[1][0][i][j] = 0.0f;
3367
3368
3369
3370
3371
3372
3373
3374

3375
3376
3377
3378
3379
3380
3381
3459
3460
3461
3462
3463
3464
3465

3466
3467
3468
3469
3470
3471
3472
3473







-
+







  }
  Tcl_SetChannelOption(interp, *ch, "-translation", "binary");
#ifdef TCL_81_API
  Tcl_SetChannelOption(interp, *ch, "-encoding", "binary");
#endif

  if (S->debug > 2) Snack_WriteLog("    Exit OpenMP3File\n");
  

  return TCL_OK;
}

int
CloseMP3File(Sound *s, Tcl_Interp *interp, Tcl_Channel *ch)
{
  if (s->debug > 2) Snack_WriteLog("    Enter CloseMP3File\n");
3392
3393
3394
3395
3396
3397
3398

3399
3400
3401
3402
























































3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551







+




+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
FreeMP3Header(Sound *s)
{
  if (s->debug > 2) Snack_WriteLog("    Enter FreeMP3Header\n");

  if (s->extHead != NULL) {
    ckfree((char *)s->extHead);
    s->extHead = NULL;
    s->extHeadType = 0;
  }

  if (s->debug > 2) Snack_WriteLog("    Exit FreeMP3Header\n");
}

int
ConfigMP3Header(Sound *s, Tcl_Interp *interp, int objc,
                Tcl_Obj *CONST objv[])
{
  mp3Info *si = (mp3Info *)s->extHead;
  int arg, index;
  static char *optionStrings[] = {
    "-bitrate", NULL
  };
  enum options {
    BITRATE
  };

  if (si == NULL || objc < 3) return 0;

  if (objc == 3) { /* get option */
    if (Tcl_GetIndexFromObj(interp, objv[2], optionStrings, "option", 0,
                            &index) != TCL_OK) {
      Tcl_AppendResult(interp, ", or\n", NULL);
      return 0;
    }

    switch ((enum options) index) {
    case BITRATE:
      {
        Tcl_SetObjResult(interp, Tcl_NewIntObj(si->bitrate));
        break;
      }
    }
  } else {
    for (arg = 2; arg < objc; arg+=2) {
      int index;

      if (Tcl_GetIndexFromObj(interp, objv[arg], optionStrings, "option", 0,
                              &index) != TCL_OK) {
        return TCL_ERROR;
      }

      if (arg + 1 == objc) {
        Tcl_AppendResult(interp, "No argument given for ",
                         optionStrings[index], " option\n", (char *) NULL);
        return 0;
      }

      switch ((enum options) index) {
      case BITRATE:
        {
          break;
        }
      }
    }
  }

  return 1;
}

Changes to snack/generic/jkFormatMP3.h.

35
36
37
38
39
40
41

42
43
44
45
46
47
48
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49







+







  int bufind;
  unsigned char buffer[BUFFER_SIZE+BUFFER_AUX];
  int append;
  int data;
  float u[2][2][32][16];
  int u_start[2];
  int u_div[2];
  int bitrate;
} mp3Info;

/* "audio.h" */

struct AUDIO_HEADER {
	int ID;
	int layer;

Changes to snack/generic/jkMixer.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or

Changes to snack/generic/jkPitchCmd.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 2001 Kåre Sjölander <kare@speech.kth.se>
 * Copyright (C) 2000-2002 Kåre Sjölander <kare@speech.kth.se>
 * Copyright (C) 1997 Philippe Langlais <felipe@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
350
351
352
353
354
355
356
357
358
359
360
361

362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384

385
386
387
388
389
390
391
350
351
352
353
354
355
356

357



358
359
360
361
362
363
364
365
366
367
368





369
370
371
372
373

374

375
376
377
378
379
380
381
382







-

-
-
-
+










-
-
-
-
-





-

-
+








  length = cst_step_max-cst_step_min+1;

  for (trame=i=0; i < longueur; i += cst_step_hamming,trame++) {
    if (i > s->length - cst_length_hamming) break;
    if (i > longueur - cst_length_hamming/2) break;
    if (quick && (Nrj[trame] < seuil_nrj) && (Dpz[trame] > seuil_dpz)) {
      Resultat[trame] = NULL;
    } else {
      Resultat[trame] = (int *) ckalloc(sizeof(int) * length); /* un peu couteux en temps */
      
      amdf(s, (int) i,Hammer,Resultat[trame],(Nrj[trame])? Nrj[trame]:1,start); 
      amdf(s, (int) i,Hammer,Resultat[trame],(Nrj[trame])? Nrj[trame]:1,start);
      for (j=0; j<length;j++) {
	if (Resultat[trame][j]>max_amdf) max_amdf = Resultat[trame][j];
	
	if (Resultat[trame][j]<min_amdf) min_amdf = Resultat[trame][j];
      }
    }
    if ((trame % 20) == 19) {
      int res = Snack_ProgressCallback(s->cmdPtr, interp, "Computing pitch",
				       0.05 + 0.95 * (double) i / longueur);
      if (res != TCL_OK) {
	for (i = 0; i < trame; i++) {
	  if (Resultat[i]) {
	    ckfree((char *) Resultat[i]);
	  }
	}
	return TCL_ERROR;
      }
    }
  }
  Snack_ProgressCallback(s->cmdPtr, interp, "Computing pitch", 1.0);
  Resultat[trame] = NULL;
  *nb_trames = (int) trame;
  

  if (debug) printf("min_amdf=%d, max_amdf=%d\n",min_amdf,max_amdf);
  return TCL_OK;
}

/* ************************************************************************ */
/*             LA MAGOUILLE DE LA RECHERCHE DU MEILLEUR CHEMIN              */
/* ************************************************************************ */
758
759
760
761
762
763
764






765
766



767
768
769
770
771
772
773
749
750
751
752
753
754
755
756
757
758
759
760
761


762
763
764
765
766
767
768
769
770
771







+
+
+
+
+
+
-
-
+
+
+







  min_nrj = min_dpz = MAX_ENTIER;

  Snack_ProgressCallback(s->cmdPtr, interp, "Computing pitch", 0.0);

  for (trame=i=0; i<longueur; i += cst_step_hamming,trame++) {
    J = minimum(s->length,(i+cst_length_hamming));
    JJ = J-1;
    if (s->length < i + start + cst_length_hamming) {
      Snack_GetSoundData(s, i+start, Signal, s->length - i + start);
      for (j = s->length - i + start; j < cst_length_hamming; j++) {
	Signal[j] = 0.0f;
      }
    } else {
    Snack_GetSoundData(s, i+start, Signal, cst_length_hamming);
    
      Snack_GetSoundData(s, i+start, Signal, cst_length_hamming);
    }    

    /* ---- nrj ---- */
    for (nrj=0.0,j=0; j<J-i; j++) 
      nrj += CARRE((double) Signal[j]);  
    
    m = Nrj[trame] = (short) (10 * log10(nrj));
    
    if (m > max_nrj) max_nrj = m;
781
782
783
784
785
786
787
788

789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
779
780
781
782
783
784
785

786
787
788
789
790





791
792
793
794
795
796
797







-
+




-
-
-
-
-







      if (sens) while ( (j<JJ-i) && (Signal[j] > Signal[j+1]) ) j++;
      else while ( (j<JJ-i) && (Signal[j] <= Signal[j+1]) ) j++;      
    }
    m = Dpz[trame] = dpz;
    
    if (m > max_dpz) max_dpz = m;
    if (m < min_dpz) min_dpz = m;
    

    if ((trame % 300) == 299) {
      int res = Snack_ProgressCallback(s->cmdPtr, interp, "Computing pitch",
				       0.05 * (double) i / longueur);
      if (res != TCL_OK) {
	for (i = 0; i < trame; i++) {
	  if (Resultat[i]) {
	    ckfree((char *) Resultat[i]);
	  }
	}
	return TCL_ERROR;
      }
    }  
  }

  seuil_nrj = min_nrj + (SEUIL_NRJ*(max_nrj-min_nrj))/100;   
  seuil_dpz = min_dpz + (SEUIL_DPZ*(max_dpz-min_dpz))/100;  
936
937
938
939
940
941
942




943
944
945
946
947
948
949
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946







+
+
+
+








  nb_trames = (longueur / cst_step_hamming) + 10;
  Nrj =  (short *) ckalloc(sizeof(short) * nb_trames);   
  Dpz =  (short *) ckalloc(sizeof(short) * nb_trames);
  Vois = (short *) ckalloc(sizeof(short) * nb_trames);
  Fo =   (short *) ckalloc(sizeof(short) * nb_trames);
  Resultat = (int **) ckalloc(sizeof(int *) * nb_trames);

  for (i = 0; i < nb_trames; i++) {
    Resultat[i] = (int *) ckalloc(sizeof(int) * (cst_step_max-cst_step_min+1));
  }

  nb_trames = nbframes = calcul_nrj_dpz(s, interp, start, longueur);

  Hamming = (double *) ckalloc(sizeof(double)*cst_length_hamming);
  Hammer = (int *) ckalloc(sizeof(int) * cst_length_hamming);
  for (i=0;i<cst_pics_amdf;i++) {
    Coeff_Amdf[i] = (RESULT *) ckalloc(sizeof(RESULT)* nb_trames);

Changes to snack/generic/jkSound.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
325
326
327
328
329
330
331















332
333
334
335
336
337
338







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







  tc = *(p+3);
  *(p+3) = *(p+4);
  *(p+4) = tc;
  
  return(d);
}

void
ByteSwapSound(Sound *s)
{
  /*
  int i, j;
  for (j = 0; j < s->nblks; j++)
    if (s->encoding == LIN16)
      for (i = 0; i < min(SBLKSIZE, s->length * s->nchannels); i++)
	s->blocks[j][i] = Snack_SwapShort(s->blocks[j][i]);
    else
      for (i = 0; i < min(LBLKSIZE, s->length * s->nchannels); i++)
	((int **)s->blocks)[j][i] = Snack_SwapLong(((int **)s->blocks)[j][i]);
	*/
}

extern struct Snack_FileFormat *snackFileFormats;

void
Snack_DeleteSound(Sound *s)
{
  jkCallback *currCB;
  Snack_FileFormat *ff;
442
443
444
445
446
447
448

449
450
451
452
453
454

455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472








473
474
475
476
477
478
479
427
428
429
430
431
432
433
434
435
436
437
438
439

440
441

442

443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471







+





-
+

-

-














+
+
+
+
+
+
+
+







    s->exact = len * s->nchannels * sampSize;
    if ((s->blocks[0] = (float *) ckalloc(s->exact)) == NULL) {
      return TCL_ERROR;
    }
    i = 1;
    s->maxlength = len;
  } else if (neededblks > s->nblks) {
    float *tmp = s->blocks[0];

    if (s->debug > 2) {
      Snack_WriteLogInt("    Allocating full block(s)", neededblks - s->nblks);
    }

    /* De-allocate any exact block */
    /* Do not count exact block, needs to be re-allocated */
    if (s->exact > 0) {
      ckfree((char *) s->blocks[0]);
      s->nblks = 0;
      s->exact = 0;
    }

    for (i = s->nblks; i < neededblks; i++) {
      if ((s->blocks[i] = (float *) ckalloc(CBLKSIZE)) == NULL) {
	break;
      }
    }
    if (i < neededblks) {
      if (s->debug > 2) Snack_WriteLogInt("    block alloc failed", i);
      for (--i; i >= s->nblks; i--) {
	ckfree((char *) s->blocks[i]);
      }
      return TCL_ERROR;
    }

    /* Copy and de-allocate any exact block */
    if (s->exact > 0) {
      memcpy(s->blocks[0], tmp, s->exact);
      ckfree((char *) tmp);
      s->exact = 0;
    }

    s->maxlength = neededblks * blockSize / s->nchannels;
  } else if (neededblks == 1 && s->exact > 0) {

    /* Reallocate to one full block */

    float *tmp = (float *) ckalloc(CBLKSIZE);

862
863
864
865
866
867
868
869


870
871
872
873
874
875
876
877
878
879
880

881

882
















883
884
885
886
887
888
889
854
855
856
857
858
859
860

861
862
863
864
865
866
867
868
869
870
871
872
873
874

875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899







-
+
+











+
-
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+








  return TCL_OK;
}

static int
configureCmd(Sound *s, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
  int arg, filearg = 0;
  int arg, filearg = 0, newobjc;
  Tcl_Obj **newobjv = NULL;
  static char *optionStrings[] = {
    "-load", "-file", "-channel", "-rate", "-frequency", "-channels",
    "-encoding", "-format", "-byteorder", "-buffersize", "-skiphead",
    "-guessproperties", "-precision", "-changecommand", "-fileformat",
    "-debug", NULL
  };
  enum options {
    OPTLOAD, OPTFILE, CHANNEL, RATE, FREQUENCY, CHANNELS, ENCODING, FORMAT,
    BYTEORDER, BUFFERSIZE, SKIPHEAD, GUESSPROPS, PRECISION, CHGCMD, FILEFORMAT,
    OPTDEBUG
  };
  Snack_FileFormat *ff;

  
  if (s->debug > 0) { Snack_WriteLog("Enter configureCmd\n"); }

  Snack_RemoveOptions(objc-2, objv+2, optionStrings, &newobjc,
		      (Tcl_Obj **) &newobjv);
  if (newobjc > 0) {
    for (ff = snackFileFormats; ff != NULL; ff = ff->nextPtr) {
      if (strcmp(s->fileType, ff->name) == 0) {
	if (ff->configureProc != NULL) {
	  if ((ff->configureProc)(s, interp, objc, objv)) return TCL_OK;
	}
      }
    }
  }
  for (arg = 0; arg <newobjc; arg++) {
    Tcl_DecrRefCount(newobjv[arg]);
  }
  ckfree((char *)newobjv);

  if (objc == 2) { /* get all options */
    Tcl_Obj *objs[6];
    
    objs[0] = Tcl_NewIntObj(s->length);
    objs[1] = Tcl_NewIntObj(s->samprate);
    if (s->encoding == SNACK_FLOAT) {
1011
1012
1013
1014
1015
1016
1017

1018
1019
1020
1021
1022
1023
1024
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035







+







  } else { /* set option */

    s->guessEncoding = -1;
    s->guessRate = -1;

    for (arg = 2; arg < objc; arg+=2) {
      int index;

      if (Tcl_GetIndexFromObj(interp, objv[arg], optionStrings, "option", 0,
			      &index) != TCL_OK) {
	return TCL_ERROR;
      }
      
      if (arg + 1 == objc) {
	Tcl_AppendResult(interp, "No argument given for ",
1366
1367
1368
1369
1370
1371
1372
1373

1374
1375
1376
1377
1378
1379
1380
1377
1378
1379
1380
1381
1382
1383

1384
1385
1386
1387
1388
1389
1390
1391







-
+








  return TCL_OK;
}

int filterSndCmd(Sound *s, Tcl_Interp *interp, int objc,
		 Tcl_Obj *CONST objv[]);

#define NSOUNDCOMMANDS   32
#define NSOUNDCOMMANDS   33
#define MAXSOUNDCOMMANDS 50

static int nSoundCommands   = NSOUNDCOMMANDS;
static int maxSoundCommands = MAXSOUNDCOMMANDS;

char *sndCmdNames[MAXSOUNDCOMMANDS] = {
  "play",
1405
1406
1407
1408
1409
1410
1411

1412
1413
1414
1415
1416
1417
1418
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430







+







  "dBPowerSpectrum",
  "pitch",
  "reverse",
  "shape",
  "datasamples",
  "filter",
  "swap",
  "power",
  NULL
};

/* NOTE: NSOUNDCOMMANDS needs updating when new commands are added. */

soundCmd *sndCmdProcs[MAXSOUNDCOMMANDS] = {
  playCmd,
1442
1443
1444
1445
1446
1447
1448
1449


1450
1451
1452

1453
1454
1455
1456
1457
1458
1459
1454
1455
1456
1457
1458
1459
1460

1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473







-
+
+



+







  convertCmd,
  dBPowerSpectrumCmd,
  pitchCmd,
  reverseCmd,
  shapeCmd,
  dataSamplesCmd,
  filterSndCmd,
  swapCmd
  swapCmd,
  powerCmd
};

soundDelCmd *sndDelCmdProcs[MAXSOUNDCOMMANDS] = {
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
1576
1577
1578
1579
1580
1581
1582



1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606







+
+
+







  s->validStart = 0;
  s->linkInfo.linkCh = NULL;
  s->inByteOrder = SNACK_NATIVE;
  s->devStr = NULL;
  s->soundTable = NULL;
  s->filterName = NULL;
  s->extHead    = NULL;
  s->extHeadType = 0;
  s->extHead2   = NULL;
  s->extHead2Type = 0;
  s->loadOffset = 0;
  s->changeCmdPtr = NULL;
  s->userFlag   = 0;
  s->userData   = NULL;

  return s;
}

Changes to snack/generic/jkSound.h.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
105
106
107
108
109
110
111



112
113
114
115
116
117
118
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121







+
+
+







  int itemRefCnt;
  int validStart;
  SnackLinkedFileInfo linkInfo;
  char *devStr;
  Tcl_HashTable *soundTable;
  char *filterName;
  char *extHead;
  char *extHead2;
  int extHeadType;
  int extHead2Type;
  int loadOffset;
  Tcl_Obj *changeCmdPtr;
  unsigned int userFlag; /* User flags, for new file formats, etc */
  char *userData;        /* User data pointer */

} Sound;

212
213
214
215
216
217
218

219

220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238


239
240
241
242
243
244
245
215
216
217
218
219
220
221
222

223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241

242
243
244
245
246
247
248
249
250







+
-
+


















-
+
+








#define HEADBUF 4096

extern char *LoadSound(Sound *s, Tcl_Interp *interp, Tcl_Obj *obj,
		       int startpos, int endpos);

extern int SaveSound(Sound *s, Tcl_Interp *interp, char *filename,
		     Tcl_Obj *obj, int objc, Tcl_Obj *CONST objv[],
		     Tcl_Obj *obj, int startpos, int len, char *type);
		     int startpos, int len, char *type);

extern int GetChannels(Tcl_Interp *interp, Tcl_Obj *obj, int *nchannels);

extern int GetEncoding(Tcl_Interp *interp, Tcl_Obj *obj, 
		       int *encoding, int *sampsize);

extern float Snack_SwapFloat(float f);

extern double Snack_SwapDouble(double d);

extern void ByteSwapSound(Sound *s);

extern void SwapIfBE(Sound *s);

extern void SwapIfLE(Sound *s);

extern int GetHeader(Sound *s, Tcl_Interp *interp, Tcl_Obj *obj);

extern int PutHeader(Sound *s, Tcl_Interp *interp, int length);
extern int PutHeader(Sound *s, Tcl_Interp *interp, int objc,
		     Tcl_Obj *CONST objv[], int length);

extern int WriteLELong(Tcl_Channel ch, long l);

extern int WriteBELong(Tcl_Channel ch, long l);

extern int SetFcname(Sound *s, Tcl_Interp *interp, Tcl_Obj *obj);

256
257
258
259
260
261
262
263


264
265
266
267
268
269
270
271
272
273
274

275
276
277
278
279



280
281
282
283
284
285
286
261
262
263
264
265
266
267

268
269
270
271
272
273
274
275
276
277
278
279

280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295







-
+
+










-
+





+
+
+








typedef int  (getHeaderProc)(Sound *s, Tcl_Interp *interp, Tcl_Channel ch,
			     Tcl_Obj *obj, char *buf);

typedef char *(extensionFileTypeProc)(char *buf);

typedef int  (putHeaderProc)(Sound *s, Tcl_Interp *interp, Tcl_Channel ch,
			     Tcl_Obj *obj, int length);
			     Tcl_Obj *obj, int objc,
			     Tcl_Obj *CONST objv[], int length);

typedef int  (openProc)(Sound *s, Tcl_Interp *interp,Tcl_Channel *ch,
			char *mode);

typedef int  (closeProc)(Sound *s, Tcl_Interp *interp, Tcl_Channel *ch);

typedef int  (readSamplesProc)(Sound *s, Tcl_Interp *interp, Tcl_Channel ch,
			       char *inBuffer, float *outBuffer, int length);

typedef int  (writeSamplesProc)(Sound *s, Tcl_Channel ch, Tcl_Obj *obj,
				float *buffer, int length);
				int start, int length);

typedef int  (seekProc)(Sound *s, Tcl_Interp *interp, Tcl_Channel ch,
			int position);

typedef void (freeHeaderProc)(Sound *s);

typedef int  (configureProc)(Sound *s, Tcl_Interp *interp, int objc,
			     Tcl_Obj *CONST objv[]);

/* Deprecated: SnackFileFormat */

typedef struct SnackFileFormat {
  char *formatName;
  guessFileTypeProc      *guessProc;
  getHeaderProc          *getHeaderProc;
303
304
305
306
307
308
309

310
311
312
313
314
315
316
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326







+







  putHeaderProc           *putHeaderProc;
  openProc                *openProc;
  closeProc               *closeProc;
  readSamplesProc         *readProc;
  writeSamplesProc        *writeProc;
  seekProc                *seekProc;
  freeHeaderProc          *freeHeaderProc;
  configureProc           *configureProc;
  struct Snack_FileFormat *nextPtr;
} Snack_FileFormat;

extern int GuessEncoding(Sound *s, unsigned char *buf, int len);

extern char *GuessFileType(char *buf, int len, int eof);

382
383
384
385
386
387
388



389
390
391
392
393
394
395
396
397
398
399
400
401




402
403
404
405
406
407



408
409
410
411
412
413
414
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434







+
+
+













+
+
+
+






+
+
+







extern int OpenMP3File(Sound *s, Tcl_Interp *interp, Tcl_Channel *ch,
		       char *mode);

extern int CloseMP3File(Sound *s, Tcl_Interp *interp, Tcl_Channel *ch);

extern void FreeMP3Header(Sound *s);

extern int ConfigMP3Header(Sound *s, Tcl_Interp *interp, int objc,
			   Tcl_Obj *CONST objv[]);

typedef enum {
  SNACK_WIN_HAMMING,
  SNACK_WIN_HANNING,
  SNACK_WIN_BARTLETT,
  SNACK_WIN_BLACKMAN,
  SNACK_WIN_RECT
} SnackWindowType;

extern int GetWindowType(Tcl_Interp *interp, char *str, SnackWindowType *type);

extern int GetChannel(Tcl_Interp *interp, char *str, int nchannels,
		      int *channel);

extern float LpcAnalysis(float *data, int N, float *f, int order);

extern void PreEmphase(float *sig, float presample, int len, float preemph);

extern double SnackCurrentTime();

extern char *Snack_InitStubs (Tcl_Interp *interp, char *version, int exact);

extern int pitchCmd(Sound *s, Tcl_Interp *interp, int objc,
		    Tcl_Obj *CONST objv[]);

extern int powerCmd(Sound *s, Tcl_Interp *interp, int objc,
		    Tcl_Obj *CONST objv[]);

extern int reverseCmd(Sound *s, Tcl_Interp *interp, int objc,
		      Tcl_Obj *CONST objv[]);

#define ITEMBUFFERSIZE 100000

extern float GetSample(SnackLinkedFileInfo *infoPtr, int index);
505
506
507
508
509
510
511
512





513
514
515
516
517
518
519
525
526
527
528
529
530
531

532
533
534
535
536
537
538
539
540
541
542
543







-
+
+
+
+
+







  struct Snack_FilterType *nextPtr;
} Snack_FilterType;

void SnackCreateFilterTypes(Tcl_Interp *interp);

extern int WriteSound(writeSamplesProc *writeProc, Sound *s,
		      Tcl_Interp *interp, Tcl_Channel ch, Tcl_Obj *obj,
		      int startpos, int len, int hdsize);
		      int startpos, int len);

extern void Snack_RemoveOptions(int objc, Tcl_Obj *CONST objv[],
				char **subOptionStrings, int *newobjc,
				Tcl_Obj **newobjv);

#ifndef MAC
#  define PBSIZE 100000
#  define NMAX 16384
#else
#  define PBSIZE 64000
#  define NMAX 8192

Changes to snack/generic/jkSoundEdit.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or

Changes to snack/generic/jkSoundEngine.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
53
54
55
56
57
58
59


60
61
62
63
64
65

66
67
68
69
70
71
72
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75







+
+






+







#define BUFSCROLLSIZE 25000
struct jkQueuedSound *rsoundQueue = NULL;

extern int debugLevel;
extern char *snackDumpFile;
static Tcl_Channel snackDumpCh = NULL;

extern struct Snack_FileFormat *snackFileFormats;

static void
RecCallback(ClientData clientData)
{
  jkQueuedSound *p;
  int nRead = 0, i, sampsleft = SnackAudioReadable(&adi);
  int size = globalRate / FPS;
  Snack_FileFormat *ff;

  if (debugLevel > 1) Snack_WriteLogInt("  Enter RecCallback", sampsleft);

  if (sampsleft > size * 2) size *= 2;
  if (sampsleft > size * 2) size = sampsleft;
  if (sampsleft < size) size = sampsleft;

91
92
93
94
95
96
97


98
99
100





101
102
103
104
105
106
107
94
95
96
97
98
99
100
101
102



103
104
105
106
107
108
109
110
111
112
113
114







+
+
-
-
-
+
+
+
+
+







      }

      for (i = 0; i < nRead * s->nchannels; i++) {
	FSAMPLE(s, (s->length - s->validStart) * s->nchannels + i) =
	  (float) shortBuffer[i];
      }

      for (ff = snackFileFormats; ff != NULL; ff = ff->nextPtr) {
	if (strcmp(s->fileType, ff->name) == 0) {
      WriteSound(NULL, s, s->interp, s->rwchan, NULL,
		 s->length - s->validStart, nRead, 0);

	  WriteSound(ff->writeProc, s, s->interp, s->rwchan, NULL,
		     s->length - s->validStart, nRead);
	}
      }
      
      Tcl_Flush(s->rwchan);
      
    } else { /* sound in memory */
      if (s->length > s->maxlength - max(sampsleft, 2 * nRead)) {
	if (Snack_ResizeSoundStorage(s, s->length + max(sampsleft, 2 * nRead)) != TCL_OK) {
	  return;
	}
209
210
211
212
213
214
215
216

217
218
219
220
221
222
223
216
217
218
219
220
221
222

223
224
225
226
227
228
229
230







-
+







      printf("P\t");
    else
      printf("D\t");
  }
  printf("\n");
}
*/
extern struct Snack_FileFormat *snackFileFormats;

extern Tcl_HashTable *filterHashTable;
extern float globalScaling;

static int
AssembleSoundChunk(int inSize)
{
  int chunkWritten = 1, writeSize = 0, size = inSize, i, j;
429
430
431
432
433
434
435
436

437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461








462
463
464
465
466
467
468
436
437
438
439
440
441
442

443
444
445
446
447
448
449
450
451


452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481







-
+








-
-















+
+
+
+
+
+
+
+







    } else { /* No filter to apply */
      if (inputExhausted) {
	p->status = SNACK_QS_DONE;
      }
      p->nWritten += nPrepared;
      outFrames = writeSize;
    }

    
    for (i = first * globalOutWidth, j = first * globalStreamWidth;
	 i < outFrames * globalOutWidth;) {
      int c;

      for (c = 0; c < globalOutWidth; c++, i++, j++) {

	switch (s->encoding) {
	case LIN16:
	case SNACK_FLOAT:
	case SNACK_DOUBLE:
	case ALAW:
	case MULAW:
	  floatBuffer[i] += fff[j];
	  break;
	case LIN32:
	  floatBuffer[i] += fff[j] / 65536.0f;
	  break;
	case LIN8:
	  floatBuffer[i] += fff[j] * 256.0f;
	  break;
	case LIN8OFFSET:
	  floatBuffer[i] += (fff[j] - 128.0f) * 256.0f;
	  break;
	case LIN24:
	  floatBuffer[i] += fff[j] / 256.0f;
	  break;
	case SNACK_FLOAT:
	case SNACK_DOUBLE:
	  if (s->maxsamp > 1.0) {
	    floatBuffer[i] += fff[j];
	  } else {
	    floatBuffer[i] += fff[j] * 65536.0f;
	  }
	  break;
	}
      }
      if (globalStreamWidth > globalOutWidth) {
	j += (globalStreamWidth - globalOutWidth);
      }
    }
582
583
584
585
586
587
588
589
590
591

592
593
594
595
596
597
598
595
596
597
598
599
600
601

602
603
604
605
606
607
608
609
610
611







-


+







      }
      p->execd = 1;
    }
   */
  }

  if (closedDown) {
    ExecSoundCmd(sCurr, EXEC_AND_CLEAN);
    CleanPlayQueue();
    wop = IDLE;
    ExecSoundCmd(sCurr, EXEC_AND_CLEAN);
    return;
  }

  if (!sCurr->blockingPlay) {
    playgrain = 10;/*max(min(PLAYGRAIN, (int) (globalLatency * 500.0)), 1);*/
    
    ptoken = Tcl_CreateTimerHandler(playgrain, (Tcl_TimerProc *) PlayCallback,
697
698
699
700
701
702
703

704
705
706
707
708
709
710
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724







+








    }
  } else { /* sound in file or channel */

    /* file or channel sound record */

    if ((rop == READ || rop == PAUSED) && (s->readStatus == READ)) {
      Snack_FileFormat *ff;
      for (p = rsoundQueue; p->sound != s; p = p->next);
      if (p->sound == s) {
	if (p->next != NULL) {
	  p->next->prev = p->prev;
	}
	if (p->prev != NULL) {
	  p->prev->next = p->next;
727
728
729
730
731
732
733
734








735
736
737
738


739
740
741
742
743
744
745
746
747
748
749
750
751
752

753
754
755





756

757
758
759


760
761
762
763
764
765
766
741
742
743
744
745
746
747

748
749
750
751
752
753
754
755
756
757


758
759
760
761
762
763
764
765
766
767
768
769
770
771
772

773
774
775
776
777
778
779
780
781

782
783


784
785
786
787
788
789
790
791
792







-
+
+
+
+
+
+
+
+


-
-
+
+













-
+



+
+
+
+
+
-
+

-
-
+
+







		    (FBLKSIZE-BUFSCROLLSIZE) * sizeof(float));
	  }
	  
	  for (i = 0; i < nRead * s->nchannels; i++) {
	    FSAMPLE(s, (s->length - s->validStart) * s->nchannels + i) =
	      (float) shortBuffer[i];
	  }
	  

	  for (ff = snackFileFormats; ff != NULL; ff = ff->nextPtr) {
	    if (strcmp(s->fileType, ff->name) == 0) {
	      WriteSound(ff->writeProc, s, s->interp, s->rwchan, NULL,
			 s->length - s->validStart, nRead);
	    }
	  }
	  /*
	  WriteSound(NULL, s, s->interp, s->rwchan, NULL,
		     (s->length - s->validStart) * s->nchannels,
		     nRead * s->nchannels, 0);
	  
		     nRead * s->nchannels);
	  */
	  Tcl_Flush(s->rwchan);

	  if (s->debug > 2) Snack_WriteLogInt("    Tcl_Read", nRead);
	  
	  s->length += nRead;
	}
	SnackAudioFlush(&adi);
	SnackAudioClose(&adi);
	Tcl_DeleteTimerHandler(rtoken);
	rop = IDLE;
	CleanRecordQueue();
      }
      if (Tcl_Seek(s->rwchan, 0, SEEK_SET) != -1) {
	PutHeader(s, interp, s->length);
	PutHeader(s, interp, 0, NULL, s->length);
	Tcl_Seek(s->rwchan, 0, SEEK_END);
      }
      if (s->storeType == SOUND_IN_FILE) {
	for (ff = snackFileFormats; ff != NULL; ff = ff->nextPtr) {
	  if (strcmp(s->fileType, ff->name) == 0) {
	    SnackCloseFile(ff->closeProc, s, interp, &s->rwchan);
	  }
	}
	Tcl_Close(interp, s->rwchan);
	/*Tcl_Close(interp, s->rwchan);*/
      }
      ckfree((char *)s->tmpbuf);
      s->tmpbuf = NULL;
      /*ckfree((char *)s->tmpbuf);
	s->tmpbuf = NULL;*/
      s->rwchan = NULL;
      s->validStart = 0;
      s->readStatus = IDLE;
      Snack_ExecCallbacks(s, SNACK_MORE_SOUND); 
    }

    /* file or channel sound play */
789
790
791
792
793
794
795
796
797


798
799
800
801
802
803
804
815
816
817
818
819
820
821


822
823
824
825
826
827
828
829
830







-
-
+
+







	}
	SnackAudioFlush(&ado);
	SnackAudioClose(&ado);
	wop = IDLE;
	Tcl_DeleteTimerHandler(ptoken);
	CleanPlayQueue();
      }	
      ckfree((char *)s->tmpbuf);
      s->tmpbuf = NULL;
      /*      ckfree((char *)s->tmpbuf);
	      s->tmpbuf = NULL;*/
      if (s->rwchan != NULL) {
	if (s->storeType == SOUND_IN_FILE) {
	  Snack_FileFormat *ff;
	  for (ff = snackFileFormats; ff != NULL; ff = ff->nextPtr) {
	    if (strcmp(s->fileType, ff->name) == 0) {
	      SnackCloseFile(ff->closeProc, s, s->interp, &s->rwchan);
	      s->rwchan = NULL;
815
816
817
818
819
820
821
822

823
824
825
826
827
828
829
841
842
843
844
845
846
847

848
849
850
851
852
853
854
855







-
+








extern char defaultOutDevice[];

int
playCmd(Sound *s, Tcl_Interp *interp, int objc,	Tcl_Obj *CONST objv[])
{
  int startPos = 0, endPos = -1, block = 0, arg, startTime = 0;
  int channels = -1, rate = -1;
  int devChannels = -1, rate = -1;
  double dStart = 0.0;
  static char *subOptionStrings[] = {
    "-output", "-start", "-end", "-command", "-blocking", "-device", "-filter",
    "-starttime", "-devicechannels", "-devicerate", NULL
  };
  enum subOptions {
    OUTPUT, STARTPOS, END, COMMAND, BLOCKING, DEVICE, FILTER, STARTTIME,
965
966
967
968
969
970
971
972

973
974
975
976
977
978
979
991
992
993
994
995
996
997

998
999
1000
1001
1002
1003
1004
1005







-
+







	if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &dStart) != TCL_OK) {
	  return TCL_ERROR;
	}
	break;
      }
    case DEVCHANNELS:
      {
	if (Tcl_GetIntFromObj(interp, objv[arg+1], &channels) != TCL_OK) {
	if (Tcl_GetIntFromObj(interp, objv[arg+1], &devChannels) != TCL_OK) {
	  return TCL_ERROR;
	}
	break;
      }
    case DEVRATE:
      {
	if (Tcl_GetIntFromObj(interp, objv[arg+1], &rate) != TCL_OK) {
989
990
991
992
993
994
995
996

997
998
999
1000
1001
1002
1003
1015
1016
1017
1018
1019
1020
1021

1022
1023
1024
1025
1026
1027
1028
1029







-
+







    s->buffersize = 1024;
    if ((s->tmpbuf = (short *) ckalloc(1024)) == NULL) {
      Tcl_AppendResult(interp, "Could not allocate buffer!", NULL);
      return TCL_ERROR;
    }
    while (tlen < s->buffersize) {
      rlen = Tcl_Read(s->rwchan, &((char *)s->tmpbuf)[tlen], 1);
      if (rlen < 0) break;
      if (rlen <= 0) break;
      s->firstNRead += rlen;
      tlen += rlen;
      if (s->forceFormat == 0) {
	s->fileType = GuessFileType((char *)s->tmpbuf, tlen, 0);
	if (strcmp(s->fileType, QUE_STRING) != 0) break;
      }
    }
1013
1014
1015
1016
1017
1018
1019
1020

1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031

1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045

1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056

1057
1058
1059
1060
1061
1062
1063
1064







-
+










-
+







      GuessEncoding(s, (unsigned char *)s->tmpbuf, s->firstNRead / 2);
    }
    ckfree((char *)s->tmpbuf);
    s->tmpbuf = NULL;
    s->firstNRead -= s->headSize;
  }
  if (s->storeType != SOUND_IN_MEMORY) {
    if (s->buffersize < s->samprate / 2) {
    /*if (s->buffersize < s->samprate / 2) {
      s->buffersize = s->samprate / 2;
    }
    if (s->tmpbuf) {
      ckfree((char *)s->tmpbuf);
    }
    if ((s->tmpbuf = (short *) ckalloc(s->buffersize * s->sampsize *
				       s->nchannels)) == NULL) {
      Tcl_AppendResult(interp, "Could not allocate buffer!", NULL);
      return TCL_ERROR;
    }

     */
    if (s->linkInfo.linkCh == NULL && s->storeType == SOUND_IN_FILE) {
      if (OpenLinkedFile(s, &s->linkInfo) != TCL_OK) {
	return TCL_ERROR;
      }
    }
  }
  if (s->storeType == SOUND_IN_MEMORY) {
1091
1092
1093
1094
1095
1096
1097
1098

1099
1100
1101

1102
1103

1104




1105
1106

1107
1108
1109
1110
1111
1112

1113
1114
1115
1116
1117

1118
1119
1120
1121
1122
1123
1124
1117
1118
1119
1120
1121
1122
1123

1124
1125
1126

1127
1128

1129
1130
1131
1132
1133
1134
1135

1136
1137
1138
1139
1140
1141

1142
1143
1144
1145
1146

1147
1148
1149
1150
1151
1152
1153
1154







-
+


-
+

-
+

+
+
+
+

-
+





-
+




-
+







    soundQueue = qs;
  } else {
    for (p = soundQueue; p->next != NULL; p = p->next);
    p->next = qs;
  }

  if (wop == IDLE) {
    if (channels == -1) {
    if (devChannels == -1) {
      globalStreamWidth = s->nchannels;
      if (s->nchannels > SnackAudioMaxNumberChannels(s->devStr)) {
	channels = SnackAudioMaxNumberChannels(s->devStr);
	devChannels = SnackAudioMaxNumberChannels(s->devStr);
      } else {
	channels = s->nchannels;
	devChannels = s->nchannels;
      }
      if (devChannels < SnackAudioMinNumberChannels(s->devStr)) {
	devChannels = SnackAudioMinNumberChannels(s->devStr);
	globalStreamWidth = devChannels;
      }
    } else {
      globalStreamWidth = channels; /* option -devicechannels used */
      globalStreamWidth = devChannels; /* option -devicechannels used */
    }
  } else {
    if (s->nchannels > globalStreamWidth) {
      globalStreamWidth = s->nchannels;
    }
    channels = s->nchannels;
    devChannels = globalStreamWidth;
  }

  if (s->filterName != NULL) {
    f->si->streamWidth = globalStreamWidth;
    f->si->outWidth    = channels;
    f->si->outWidth    = devChannels;
    f->si->rate        = rate;
    (f->startProc)(f, f->si);
  }

  if (!((wop == IDLE) && (s->writeStatus == IDLE))) {
    s->writeStatus = WRITE;

1137
1138
1139
1140
1141
1142
1143
1144

1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158

1159
1160
1161
1162
1163
1164
1165
1167
1168
1169
1170
1171
1172
1173

1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187

1188
1189
1190
1191
1192
1193
1194
1195







-
+













-
+







  ado.debug = s->debug;
  if (s->storeType == SOUND_IN_FILE) {
    s->rwchan = NULL;
  }    
  wop = WRITE;
  s->writeStatus = WRITE;

  if (SnackAudioOpen(&ado, interp, s->devStr, PLAY, rate, channels,
  if (SnackAudioOpen(&ado, interp, s->devStr, PLAY, rate, devChannels,
		     LIN16) != TCL_OK) {
    wop = IDLE;
    s->writeStatus = IDLE;
    return TCL_ERROR;
  }
  if (snackDumpFile) {
    snackDumpCh = Tcl_OpenFileChannel(interp, snackDumpFile, "w", 438);
    Tcl_SetChannelOption(interp, snackDumpCh, "-translation", "binary");
#ifdef TCL_81_API
    Tcl_SetChannelOption(interp, snackDumpCh, "-encoding", "binary");
#endif
  }
  globalRate = rate;
  globalOutWidth = channels;
  globalOutWidth = devChannels;
  globalNWritten = 0;
  if (s->writeStatus == WRITE && s->readStatus == READ) {
    globalNFlowThrough++;
  }
  sCurr = s;
  s->blockingPlay = block;
  corr = 0;
1319
1320
1321
1322
1323
1324
1325












1326


1327
1328
1329
1330
1331
1332
1333
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367

1368
1369
1370
1371
1372
1373
1374
1375
1376







+
+
+
+
+
+
+
+
+
+
+
+
-
+
+







    if ((s->tmpbuf = (short *) ckalloc(s->buffersize * s->sampsize * 
				       s->nchannels)) == NULL) {
      Tcl_AppendResult(interp, "Could not allocate buffer!", NULL);
      return TCL_ERROR;
    }
    
    if (s->storeType == SOUND_IN_FILE) {
      Snack_FileFormat *ff;

      for (ff = snackFileFormats; ff != NULL; ff = ff->nextPtr) {
	if (strcmp(s->fileType, ff->name) == 0) {
	  if (SnackOpenFile(ff->openProc, s, interp, &s->rwchan, "w") !=
	      TCL_OK) {
	    return TCL_ERROR;
	  }
	}
      }

      /*
      s->rwchan = Tcl_OpenFileChannel(interp, s->fcname, "w", 420);
	s->rwchan = Tcl_OpenFileChannel(interp, s->fcname, "w", 420);
      */
      if (s->rwchan != NULL) {
	mode = TCL_WRITABLE;
      }
    } else {
      s->rwchan = Tcl_GetChannel(interp, s->fcname, &mode);
    }
    
1341
1342
1343
1344
1345
1346
1347
1348

1349
1350
1351
1352
1353
1354
1355
1384
1385
1386
1387
1388
1389
1390

1391
1392
1393
1394
1395
1396
1397
1398







-
+







    if (!(mode & TCL_WRITABLE)) {
      Tcl_AppendResult(interp, "channel \"", s->fcname, 
		       "\" wasn't opened for writing", NULL);
      s->rwchan = NULL;
      return TCL_ERROR;
    }
    
    if (PutHeader(s, interp, -1) < 0) {
    if (PutHeader(s, interp, 0, NULL, -1) < 0) {
      return TCL_ERROR;
    }
    s->validStart = 0;
  }
  Snack_ResizeSoundStorage(s, FBLKSIZE);

  if (rop == IDLE || rop == PAUSED) {
1583
1584
1585
1586
1587
1588
1589


1590
1591
1592
1593
1594
1595
1596
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641







+
+







    SnackAudioClose(&adi);
  }
  if (wop != IDLE) {
    SnackAudioFlush(&ado);
    SnackAudioClose(&ado);
  }
  SnackAudioFree();
  rop = IDLE;
  wop = IDLE;
}

/*
 *----------------------------------------------------------------------
 *
 * SnackCurrentTime --
 *

Changes to snack/generic/jkSoundFile.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
719
720
721
722
723
724
725
726

727
728
729
730
731
732
733
719
720
721
722
723
724
725

726
727
728
729
730
731
732
733







-
+







  if (s->debug > 1) Snack_WriteLogInt("  Exit ReadSound", s->length);

  return TCL_OK;
}

int
WriteSound(writeSamplesProc *writeProc, Sound *s, Tcl_Interp *interp,
	   Tcl_Channel ch, Tcl_Obj *obj, int startpos, int len, int hdsize)
	   Tcl_Channel ch, Tcl_Obj *obj, int startpos, int len)
{
  int i = 0, j;
  short sh;
  int   is;
  float fs;
  unsigned char uc;
  char c;
888
889
890
891
892
893
894
895
896


897
898
899




900
901






902
903
904
905
906
907
908
909
910


911
912
913
914


915
916
917
918
919
920
921
888
889
890
891
892
893
894


895
896
897


898
899
900
901
902

903
904
905
906
907
908
909
910
911
912
913
914
915


916
917
918
919


920
921
922
923
924
925
926
927
928







-
-
+
+

-
-
+
+
+
+

-
+
+
+
+
+
+







-
-
+
+


-
-
+
+







					   (double)(i-startpos)/len);
	  if (res != TCL_OK) {
	    return TCL_ERROR;
	  }
	}
      }
    } else { /* writeProc != NULL */
      int tot = len, n = 0;
      
      int tot = len;

      while (tot > 0) {
	int size = min(tot, FBLKSIZE);
	(writeProc)(s, ch, obj, s->blocks[n], size);
	int size = min(tot, FBLKSIZE/2), res;

	(writeProc)(s, ch, obj, startpos, size);

	tot -= size;
	n++;
	startpos += size;
	res = Snack_ProgressCallback(s->cmdPtr, interp, "Writing sound",
				     1.0-(double)tot/len);
	if (res != TCL_OK) {
	  return TCL_ERROR;
	}
      }
    }
    Snack_ProgressCallback(s->cmdPtr, interp, "Writing sound", 1.0);
  } else { /* ch == NULL */
    unsigned char *p = NULL;
    
    if (useOldObjAPI) {
      Tcl_SetObjLength(obj, hdsize + len * s->sampsize);
      p = (unsigned char *) &obj->bytes[hdsize];
      Tcl_SetObjLength(obj, s->headSize + len * s->sampsize);
      p = (unsigned char *) &obj->bytes[s->headSize];
    } else {
#ifdef TCL_81_API
      p = Tcl_SetByteArrayLength(obj, hdsize +len * s->sampsize);
      p = &p[hdsize];
      p = Tcl_SetByteArrayLength(obj, s->headSize +len * s->sampsize);
      p = &p[s->headSize];
#endif
    }
    for (i = startpos, j = 0; i < startpos + len; i++, j++) {
      short *sp = (short *) p;
      int   *ip = (int *) p;
      float *fp = (float *) p;
      char  *cp = (char *) p;
1271
1272
1273
1274
1275
1276
1277
1278

1279


1280

1281
1282
1283
1284
1285
1286
1287
1278
1279
1280
1281
1282
1283
1284

1285
1286
1287
1288

1289
1290
1291
1292
1293
1294
1295
1296







-
+

+
+
-
+







  s->headSize = s->skipBytes;

  return TCL_OK;
}

static int
PutRawHeader(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, Tcl_Obj *obj,
	     int len)
	     int objc, Tcl_Obj *CONST objv[], int len)
{
  s->headSize = 0;
  
  return(0);
  return TCL_OK;
}

#define NIST_HEADERSIZE 1024

static int
GetSmpHeader(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, Tcl_Obj *obj,
	     char *buf)
1356
1357
1358
1359
1360
1361
1362
1363

1364
1365
1366
1367
1368
1369
1370
1365
1366
1367
1368
1369
1370
1371

1372
1373
1374
1375
1376
1377
1378
1379







-
+







  }

  return TCL_OK;
}

static int
PutSmpHeader(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, Tcl_Obj *obj,
	     int len)
	     int objc, Tcl_Obj *CONST objv[], int len)
{
  int i = 0;
  char buf[HEADBUF];

  if (s->encoding != LIN16) {
    Tcl_AppendResult(interp, "Unsupported encoding format", NULL);
    return -1;
1396
1397
1398
1399
1400
1401
1402

1403
1404


1405


1406
1407
1408
1409
1410
1411
1412
1405
1406
1407
1408
1409
1410
1411
1412


1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424







+
-
-
+
+

+
+







      unsigned char *p = Tcl_SetByteArrayLength(obj, NIST_HEADERSIZE);
      memcpy(p, buf, NIST_HEADERSIZE);
#endif
    }
  }
  s->inByteOrder = SNACK_NATIVE;
  s->swap = 0;
  s->headSize = NIST_HEADERSIZE;

  return(NIST_HEADERSIZE);
  
  return TCL_OK;
}

#define SNACK_SD_INT 20

static int
GetSdHeader(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, Tcl_Obj *obj,
	    char *buf)
{
  int datastart, len, i, j;
  double freq = 16000.0;
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445




















1446
1447
1448
1449
1450


1451
1452
1453
1454
1455
1456
1457
1448
1449
1450
1451
1452
1453
1454



1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477


1478
1479
1480
1481
1482
1483
1484
1485
1486







-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+



-
-
+
+







	  char c = buf[i+j];
	  
	  buf[i+j] = buf[i+7-j];
	  buf[i+7-j] = c;
	}
      }
      memcpy(&start, &buf[i], 8);
    }
  }


      if (s->extHead != NULL && s->extHeadType != SNACK_SD_INT) {
	Snack_FileFormat *ff;
	
	for (ff = snackFileFormats; ff != NULL; ff = ff->nextPtr) {
	  if (strcmp(s->fileType, ff->name) == 0) {
	    if (ff->freeHeaderProc != NULL) {
	      (ff->freeHeaderProc)(s);
	    }
	  }
	}
      }
      if (s->extHead == NULL) {
	s->extHead = (char *) ckalloc(sizeof(double));
	memcpy(s->extHead, &buf[i], sizeof(double));
	s->extHeadType = SNACK_SD_INT;
      }
    }
  }
  
  s->encoding = LIN16;
  s->sampsize = 2;
  s->nchannels = 1;
  s->samprate = (short) freq;
  s->loadOffset = (int) (start * s->samprate + 0.5);
  s->samprate = (int) freq;
  s->loadOffset = 0; /*(int) (start * s->samprate + 0.5);*/

  if (ch != NULL) {
    Tcl_Seek(ch, 0, SEEK_END);
    len = Tcl_Tell(ch);
    if (len == 0 || len < datastart) {
      Tcl_AppendResult(interp, "Failed reading SD header", NULL);
      return TCL_ERROR;
1471
1472
1473
1474
1475
1476
1477
















































1478
1479
1480
1481
1482
1483
1484
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    }
  }
  s->headSize = datastart;
  SwapIfLE(s);

  return TCL_OK;
}

static int
ConfigSdHeader(Sound *s, Tcl_Interp *interp, int objc,
                Tcl_Obj *CONST objv[])
{
  int index;
  static char *optionStrings[] = {
    "-start_time", NULL
  };
  enum options {
    STARTTIME
  };

  if (s->extHeadType != SNACK_SD_INT || objc < 3) return 0;

  if (objc == 3) { /* get option */
    if (Tcl_GetIndexFromObj(interp, objv[2], optionStrings, "option", 0,
                            &index) != TCL_OK) {
      Tcl_AppendResult(interp, ", or\n", NULL);
      return 0;
    }

    switch ((enum options) index) {
    case STARTTIME:
      {
	double *start = (double *) s->extHead;
        Tcl_SetObjResult(interp, Tcl_NewDoubleObj(*start));
        break;
      }
    }
  }

  return 1;
}

static void
FreeSdHeader(Sound *s)
{
  if (s->debug > 2) Snack_WriteLog("    Enter FreeSdHeader\n");

  if (s->extHead != NULL) {
    ckfree((char *)s->extHead);
    s->extHead = NULL;
    s->extHeadType = 0;
  }
  
  if (s->debug > 2) Snack_WriteLog("    Exit FreeSdHeader\n");
}

#define SND_FORMAT_MULAW_8   1
#define SND_FORMAT_LINEAR_8  2
#define SND_FORMAT_LINEAR_16 3
#define SND_FORMAT_LINEAR_24 4
#define SND_FORMAT_LINEAR_32 5
#define SND_FORMAT_FLOAT     6
1539
1540
1541
1542
1543
1544
1545



1546
1547
1548
1549
1550
1551
1552

1553
1554
1555
1556
1557
1558
1559
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631

1632
1633
1634
1635
1636
1637
1638
1639







+
+
+






-
+







    break;
  default:
    Tcl_AppendResult(interp, "Unsupported AU format", NULL);
    return TCL_ERROR;
  }
  s->samprate = GetBELong(buf, 16);
  s->nchannels = GetBELong(buf, 20);
  if (hlen < 24) {
    hlen = 24;
  }
  s->headSize = hlen;
  nsamp = GetBELong(buf, 8) / (s->sampsize * s->nchannels);

  if (ch != NULL) {
    Tcl_Seek(ch, 0, SEEK_END);
    nsampfile = (Tcl_Tell(ch) - hlen) / (s->sampsize * s->nchannels);
    if (nsampfile < nsamp || nsamp == 0) {
    if (nsampfile < nsamp || nsamp <= 0) {
      nsamp = nsampfile;
    }
  }
  if (obj != NULL) {
    if (useOldObjAPI) {
      nsamp = (obj->length - hlen) / (s->sampsize * s->nchannels);
    } else {
1573
1574
1575
1576
1577
1578
1579
1580

1581
1582
1583
1584
1585
1586
1587
1653
1654
1655
1656
1657
1658
1659

1660
1661
1662
1663
1664
1665
1666
1667







-
+







  SwapIfLE(s);

  return TCL_OK;
}

static int
PutAuHeader(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, Tcl_Obj *obj,
	    int len)
	    int objc, Tcl_Obj *CONST objv[], int len)
{
  int fmt = 0;
  char buf[HEADBUF];

  if (s->debug > 2) Snack_WriteLog("    Saving AU/SND\n");

  PutBELong(buf, 0, 0x2E736E64);
1638
1639
1640
1641
1642
1643
1644

1645
1646


1647
1648
1649
1650
1651
1652
1653
1654

1655
1656
1657
1658
1659
1660
1661
1718
1719
1720
1721
1722
1723
1724
1725


1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743







+
-
-
+
+








+







    }
  }

  if (len == -1) {
    SwapIfLE(s);
  }
  s->inByteOrder = SNACK_BIGENDIAN;
  s->headSize = AU_HEADERSIZE;

  return(AU_HEADERSIZE);
  
  return TCL_OK;
}

#define WAVE_FORMAT_PCM	1
#ifndef WIN
#  define WAVE_FORMAT_IEEE_FLOAT 3
#  define WAVE_FORMAT_ALAW  6
#  define WAVE_FORMAT_MULAW 7
#endif
#define WAVE_EX		(-2)	/* (OxFFFE) in a 2-byte word */

static int
GetHeaderBytes(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, char *buf, 
	       int len)
{
  int rlen = Tcl_Read(ch, &buf[s->firstNRead], len - s->firstNRead);

1686
1687
1688
1689
1690
1691
1692




1693
1694
1695
1696
1697
1698
1699
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785







+
+
+
+







	  return TCL_ERROR;
	}
      }
      fmt = GetLEShort(buf, i+8);
      s->nchannels = GetLEShort(buf, i+10);
      s->samprate  = GetLELong(buf, i+12);
      s->sampsize  = GetLEShort(buf, i+22) / 8;

      /* For WAVE-EX, the format is the first two bytes of the GUID */
      if (fmt == WAVE_EX)
	fmt = GetLEShort(buf, i+32);

      switch (fmt) {
      case WAVE_FORMAT_PCM:
	if (s->sampsize == 1) {
	  s->encoding = LIN8OFFSET;
	} else if (s->sampsize == 2) {
	  s->encoding = LIN16;
1813
1814
1815
1816
1817
1818
1819
1820

1821
1822
1823
1824
1825
1826
1827
1899
1900
1901
1902
1903
1904
1905

1906
1907
1908
1909
1910
1911
1912
1913







-
+







  return TCL_OK;
}

#define SNACK_WAV_HEADERSIZE 44

static int
PutWavHeader(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, Tcl_Obj *obj,
	     int len)
	     int objc, Tcl_Obj *CONST objv[], int len)
{
  char buf[HEADBUF];

  sprintf(&buf[0], "RIFF");
  if (len != -1) {
    PutLELong(buf, 4, len * s->sampsize * s->nchannels + 36);
  } else {
1869
1870
1871
1872
1873
1874
1875

1876
1877


1878
1879
1880
1881
1882
1883
1884
1955
1956
1957
1958
1959
1960
1961
1962


1963
1964
1965
1966
1967
1968
1969
1970
1971







+
-
-
+
+







#ifdef TCL_81_API
      unsigned char *p = Tcl_SetByteArrayLength(obj, SNACK_WAV_HEADERSIZE);
      memcpy(p, buf, SNACK_WAV_HEADERSIZE);
#endif
    }
  }
  s->inByteOrder = SNACK_LITTLEENDIAN;
  s->headSize = SNACK_WAV_HEADERSIZE;

  return(SNACK_WAV_HEADERSIZE);
  
  return TCL_OK;
}

/* See http://www.borg.com/~jglatt/tech/aiff.htm */

static unsigned long
ConvertFloat(unsigned char *buffer)
{
1923
1924
1925
1926
1927
1928
1929



1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950

1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967



1968
1969
1970
1971
1972
1973
1974
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039

2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067







+
+
+




















-
+

















+
+
+







  if (littleEndian) {
    value = Snack_SwapLong(value);
  }
  buffer[0] = 0x40;
  memcpy(buffer + 2, &value, sizeof(long));
}

#define ICEILV(n,m)	(((n) + ((m) - 1)) / (m))	/* int n,m >= 0 */
#define RNDUPV(n,m)	((m) * ICEILV (n, m))		/* Round up */

static int
GetAiffHeader(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, Tcl_Obj *obj,
	      char *buf)
{
  int bits = 0, offset = 0, i = 12, chunkLen = 4;

  if (s->debug > 2) Snack_WriteLog("    Reading AIFF header\n");
  
  /* buf[] = "FORMxxxxAIFF" */

  while (1) {
    if (strncasecmp("COMM", &buf[i], strlen("COMM")) == 0) {
      chunkLen = GetBELong(buf, i + 4) + 8;
      if (s->firstNRead < i + chunkLen) {
	if (GetHeaderBytes(s, interp, ch, buf, i + chunkLen) != TCL_OK) {
	  return TCL_ERROR;
	}
      }
      s->nchannels = GetBEShort(buf, i + 8);
      bits = GetBEShort(buf, i + 14);
      
      bits = RNDUPV (bits, 8);
      switch (bits) {
      case 8:
	s->encoding = LIN8;
	s->sampsize = 1;
	break;
      case 16:
	s->encoding = LIN16;
	s->sampsize = 2;
	break;
      case 24:
	s->encoding = LIN24;
	s->sampsize = 3;
	break;
      case 32:
	s->encoding = LIN32;
	s->sampsize = 4;
	break;
      default:
	Tcl_AppendResult(interp, "Unsupported AIFF format", NULL);
	return TCL_ERROR;
      }
      s->samprate = ConvertFloat((unsigned char *)&buf[i+16]);
      if (s->debug > 3) {
	Snack_WriteLogInt("      COMM chunk parsed", chunkLen);
      }
    } else if (strncasecmp("SSND", &buf[i], strlen("SSND")) == 0) {
      chunkLen = 16;
2004
2005
2006
2007
2008
2009
2010
2011

2012
2013
2014
2015
2016
2017
2018
2097
2098
2099
2100
2101
2102
2103

2104
2105
2106
2107
2108
2109
2110
2111







-
+







  return TCL_OK;
}

#define SNACK_AIFF_HEADERSIZE 54

int
PutAiffHeader(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, Tcl_Obj *obj,
	      int len)
	      int objc, Tcl_Obj *CONST objv[], int len)
{
  char buf[HEADBUF];

  if (s->encoding == LIN8OFFSET || s->encoding == ALAW ||
      s->encoding == MULAW || s->encoding == SNACK_FLOAT) {
    Tcl_AppendResult(interp, "Unsupported encoding format", NULL);
    return -1;
2052
2053
2054
2055
2056
2057
2058

2059
2060


2061
2062
2063
2064
2065
2066
2067
2145
2146
2147
2148
2149
2150
2151
2152


2153
2154
2155
2156
2157
2158
2159
2160
2161







+
-
-
+
+







#ifdef TCL_81_API
      unsigned char *p = Tcl_SetByteArrayLength(obj, SNACK_AIFF_HEADERSIZE);
      memcpy(p, buf, SNACK_AIFF_HEADERSIZE);
#endif
    }
  }
  s->inByteOrder = SNACK_BIGENDIAN;
  s->headSize = SNACK_AIFF_HEADERSIZE;

  return(SNACK_AIFF_HEADERSIZE);
  
  return TCL_OK;
}

static int
GetCslHeader(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, Tcl_Obj *obj,
	     char *buf)
{
  int tmp1, tmp2, nsamp = 0, nsampfile, i = 12, chunkLen;
2106
2107
2108
2109
2110
2111
2112
2113
2114

2115
2116
2117
2118
2119
2120
2121

2122
2123
2124
2125
2126
2127
2128
2200
2201
2202
2203
2204
2205
2206

2207
2208
2209
2210
2211
2212
2213

2214
2215
2216
2217
2218
2219
2220
2221
2222







-

+





-

+







      if (tmp1 != -1 && tmp2 != -1) {
	s->nchannels = 2;
      }
      if (s->debug > 3) {
	Snack_WriteLogInt("      HDR8 block parsed", chunkLen);
      }
    } else if (strncasecmp("SDA_", &buf[i], strlen("SDA_")) == 0) {
      nsamp = GetLELong(buf, i + 4) / (s->sampsize * s->nchannels);
      s->nchannels  = 1;
      nsamp = GetLELong(buf, i + 4) / (s->sampsize * s->nchannels);
      if (s->debug > 3) {
	Snack_WriteLogInt("      SDA_ block parsed", nsamp);
      }
      break;
    } else if (strncasecmp("SD_B", &buf[i], strlen("SD_B")) == 0) {
      nsamp = GetLELong(buf, i + 4) / (s->sampsize * s->nchannels);
      s->nchannels  = 1;
      nsamp = GetLELong(buf, i + 4) / (s->sampsize * s->nchannels);
      if (s->debug > 3) {
	Snack_WriteLogInt("      SD_B block parsed", nsamp);
      }
      break;
    } else if (strncasecmp("SDAB", &buf[i], strlen("SDAB")) == 0) {
      nsamp = GetLELong(buf, i + 4) / (s->sampsize * s->nchannels);
      if (s->debug > 3) {
2188
2189
2190
2191
2192
2193
2194
2195

2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206

2207
2208
2209
2210
2211
2212
2213
2282
2283
2284
2285
2286
2287
2288

2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299

2300
2301
2302
2303
2304
2305
2306
2307







-
+










-
+







}

#define SNACK_CSL_HEADERSIZE 88
#define CSL_DATECOMMAND "clock format [clock seconds] -format {%b %d %T %Y}"

static int
PutCslHeader(Sound *s, Tcl_Interp *interp, Tcl_Channel ch, Tcl_Obj *obj,
	     int len)
	     int objc, Tcl_Obj *CONST objv[], int len)
{
  char buf[HEADBUF];

  if (s->encoding != LIN16) {
    Tcl_AppendResult(interp, "Unsupported encoding format", NULL);
    return -1;
  }
  
  sprintf(&buf[0], "FORMDS16");
  if (len != -1) {
    PutLELong(buf, 8, len * s->sampsize * s->nchannels + 78);
    PutLELong(buf, 8, len * s->sampsize * s->nchannels + 76);
  } else {
    SwapIfBE(s);
    PutLELong(buf, 8, 0);
  }
  sprintf(&buf[12], "HEDR");
  PutLELong(buf, 16, 32);
  Tcl_GlobalEvalObj(s->interp, Tcl_NewStringObj(CSL_DATECOMMAND, -1));
2249
2250
2251
2252
2253
2254
2255

2256
2257


2258
2259
2260
2261
2262
2263







2264
2265

2266
2267
2268
2269
2270
2271
2272
2343
2344
2345
2346
2347
2348
2349
2350


2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366

2367
2368
2369
2370
2371
2372
2373
2374







+
-
-
+
+






+
+
+
+
+
+
+

-
+







#ifdef TCL_81_API
      unsigned char *p = Tcl_SetByteArrayLength(obj, SNACK_CSL_HEADERSIZE);
      memcpy(p, buf, SNACK_CSL_HEADERSIZE);
#endif
    }
  }
  s->inByteOrder = SNACK_LITTLEENDIAN;
  s->headSize = SNACK_CSL_HEADERSIZE;

  return(SNACK_CSL_HEADERSIZE);
  
  return TCL_OK;
}

int
SnackOpenFile(openProc *openProc, Sound *s, Tcl_Interp *interp,
	      Tcl_Channel *ch, char *mode)
{
  int permissions;

  if (strcmp(mode, "r") == 0) {
    permissions = 0;
  } else {
    permissions = 420;
  }
  if (openProc == NULL) {
    if ((*ch = Tcl_OpenFileChannel(interp, s->fcname, mode, 0)) == 0) {
    if ((*ch = Tcl_OpenFileChannel(interp, s->fcname, mode, permissions))==0) {
      return TCL_ERROR;
    }
    Tcl_SetChannelOption(interp, *ch, "-translation", "binary");
#ifdef TCL_81_API
    Tcl_SetChannelOption(interp, *ch, "-encoding", "binary");
#endif
  } else {
2350
2351
2352
2353
2354
2355
2356
2357

2358
2359
2360
2361

2362
2363
2364
2365
2366
2367

2368
2369

2370
2371
2372
2373
2374
2375
2376
2377


2378
2379
2380
2381

2382

2383
2384

2385
2386
2387
2388
2389
2390
2391
2392
2393
2394

2395
2396
2397
2398
2399
2400
2401
2452
2453
2454
2455
2456
2457
2458

2459
2460
2461
2462

2463
2464
2465
2466
2467
2468
2469
2470
2471

2472
2473
2474




2475

2476
2477
2478
2479
2480

2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495

2496
2497
2498
2499
2500
2501
2502
2503







-
+



-
+






+

-
+


-
-
-
-

-
+
+



-
+

+


+









-
+







  if (s->debug > 1) Snack_WriteLog("  Exit LoadSound\n");

  return(s->fileType);
}

int
SaveSound(Sound *s, Tcl_Interp *interp, char *filename, Tcl_Obj *obj,
	  int startpos, int len, char *type)
	  int objc, Tcl_Obj *CONST objv[], int startpos, int len, char *type)
{
  Tcl_Channel ch = NULL;
  Snack_FileFormat *ff;
  int hdsize;
  char *tmp = s->fcname;

  if (s->debug > 1) Snack_WriteLog("  Enter SaveSound\n");

  for (ff = snackFileFormats; ff != NULL; ff = ff->nextPtr) {
    if (strcmp(type, ff->name) == 0) {
      if (ff->putHeaderProc != NULL) {
	s->fcname = filename;
	if (filename != NULL) {
	  if ((ch = Tcl_OpenFileChannel(interp, filename, "w", 420)) == 0) {
	  if (SnackOpenFile(ff->openProc, s, interp, &ch, "w") != TCL_OK) {
	    return TCL_ERROR;
	  }
	  Tcl_SetChannelOption(interp, ch, "-translation", "binary");
#ifdef TCL_81_API
	  Tcl_SetChannelOption(interp, ch, "-encoding", "binary");
#endif
	}
	if ((hdsize = (ff->putHeaderProc)(s, interp, ch, obj, len)) < 0) {
	if ((ff->putHeaderProc)(s, interp, ch, obj, objc, objv, len)
	    != TCL_OK) {
	  return TCL_ERROR;
	}
	if (WriteSound(ff->writeProc, s, interp, ch, obj, startpos,
		       len, hdsize) != TCL_OK) {
		       len) != TCL_OK) {
	  Tcl_AppendResult(interp, "Error while writing", NULL);
	  s->fcname = tmp;
	  return TCL_ERROR;
	}
	s->fcname = tmp;
      } else {
	Tcl_AppendResult(interp, "Unsupported save format", NULL);
	return TCL_ERROR;
      }
      break;
    }
  }

  if (ch != NULL) {
    Tcl_Close(interp, ch);
    SnackCloseFile(ff->closeProc, s, interp, &ch);
  }

  if (s->debug > 1) Snack_WriteLog("  Exit SaveSound\n");

  return TCL_OK;
}

2566
2567
2568
2569
2570
2571
2572























2573
2574
2575
2576
2577

2578

2579
2580
2581
2582
2583
2584
2585
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701

2702
2703
2704
2705
2706
2707
2708
2709
2710
2711







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+




-
+

+







    Tcl_SetObjResult(interp, Tcl_NewStringObj(filetype, -1));
  }

  if (s->debug > 0) Snack_WriteLog("Exit readCmd\n");

  return TCL_OK;
}

void
Snack_RemoveOptions(int objc, Tcl_Obj *CONST objv[], char **subOptionStrings,
		    int *newobjc, Tcl_Obj **newobjv)
{
  int arg, n = 0;
  Tcl_Obj **new = NULL;

  if ((new = (Tcl_Obj **) ckalloc(sizeof(Tcl_Obj *) * objc)) == NULL) {
    return;
  }
  for (arg = 0; arg < objc; arg+=2) {
    int index;
    
    if (Tcl_GetIndexFromObj(NULL, objv[arg], subOptionStrings,
			    NULL, 0, &index) != TCL_OK) {
      new[n++] = Tcl_DuplicateObj(objv[arg]);
      if (n < objc) new[n++] = Tcl_DuplicateObj(objv[arg+1]);
    }
  }
  *newobjc = n;
  *newobjv = (Tcl_Obj *) new;
}

int
writeCmd(Sound *s, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
  int startpos = 0, endpos = s->length, arg, len;
  int startpos = 0, endpos = s->length, arg, len, newobjc;
  char *string, *filetype = NULL;
  Tcl_Obj **newobjv = NULL;
  static char *subOptionStrings[] = {
    "-start", "-end", "-fileformat", "-progress", "-byteorder", NULL
  };
  enum subOptions {
    START, END, FILEFORMAT, PROGRESS, BYTEORDER
  };

2596
2597
2598
2599
2600
2601
2602
2603

2604
2605

2606
2607
2608
2609
2610
2611
2612
2722
2723
2724
2725
2726
2727
2728

2729
2730

2731
2732
2733
2734
2735
2736
2737
2738







-
+

-
+







    Tcl_DecrRefCount(s->cmdPtr);
    s->cmdPtr = NULL;
  }

  for (arg = 3; arg < objc; arg+=2) {
    int index;
	
    if (Tcl_GetIndexFromObj(interp, objv[arg], subOptionStrings,
    if (Tcl_GetIndexFromObj(NULL, objv[arg], subOptionStrings,
			    "option", 0, &index) != TCL_OK) {
      return TCL_ERROR;
      continue;
    }
	
    if (arg + 1 == objc) {
      Tcl_AppendResult(interp, "No argument given for ",
		       subOptionStrings[index], " option", (char *) NULL);
      return TCL_ERROR;
    }
2660
2661
2662
2663
2664
2665
2666
2667




2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684


2685
2686
2687






2688
2689
2690
2691
2692
2693
2694
2786
2787
2788
2789
2790
2791
2792

2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812

2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830







-
+
+
+
+
















-
+
+



+
+
+
+
+
+







  }
  len = s->length;
  if (endpos >= len) endpos = len;
  if (endpos < 0)    endpos = len;
  if (endpos > startpos) len -= (len - endpos);
  if (startpos > endpos) return TCL_OK;
  if (startpos > 0) len -= startpos; else startpos = 0;
      

  Snack_RemoveOptions(objc-3, objv+3, subOptionStrings, &newobjc,
		      (Tcl_Obj **) &newobjv);

  if (objc < 3) {
    Tcl_AppendResult(interp, "No file name given", NULL);
    return TCL_ERROR;
  }
  string = Tcl_GetStringFromObj(objv[2], NULL);
  if (filetype == NULL) {
    filetype = NameGuessFileType(string);
  }
  if (strlen(string) == 0) {
    return TCL_OK;
  }
  if (s->storeType != SOUND_IN_MEMORY) {
    if (s->linkInfo.linkCh == NULL) {
      OpenLinkedFile(s, &s->linkInfo);
    }
  }
  if (SaveSound(s, interp, string, NULL, startpos, len, filetype)==TCL_ERROR) {
  if (SaveSound(s, interp, string, NULL, newobjc, (Tcl_Obj **CONST) newobjv,
		startpos, len, filetype) == TCL_ERROR) {
    return TCL_ERROR;
  }


  for (arg = 0; arg <newobjc; arg++) {
    Tcl_DecrRefCount(newobjv[arg]);
  }
  ckfree((char *)newobjv);

  if (s->debug > 0) { Snack_WriteLog("Exit writeCmd\n"); }

  return TCL_OK;
} /* writeCmd */

int
dataCmd(Sound *s, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
2768
2769
2770
2771
2772
2773
2774
2775

2776
2777
2778
2779
2780
2781
2782
2904
2905
2906
2907
2908
2909
2910

2911
2912
2913
2914
2915
2916
2917
2918







-
+







    len = s->length;
    if (endpos >= len) endpos = len;
    if (endpos < 0)    endpos = len;
    if (endpos > startpos) len -= (len - endpos);
    if (startpos > endpos) return TCL_OK;
    if (startpos > 0) len -= startpos; else startpos = 0;

    if (SaveSound(s, interp, NULL, new, startpos, len, filetype)
    if (SaveSound(s, interp, NULL, new, objc-2, objv+2, startpos, len,filetype)
	== TCL_ERROR) {
      return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, new);
  } else { /* variable -> sound */
    int arg, startpos = 0, endpos = -1;
    char *filetype;
2909
2910
2911
2912
2913
2914
2915
2916

2917
2918
2919
2920
2921



2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937


2938
2939
2940
2941
2942
2943
2944
3045
3046
3047
3048
3049
3050
3051

3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085







-
+





+
+
+
















+
+







} /* dataCmd */

int
GetHeader(Sound *s, Tcl_Interp *interp, Tcl_Obj *obj)
{
  Snack_FileFormat *ff;
  Tcl_Channel ch = NULL;
  int status = TCL_OK;
  int status = TCL_OK, openedOk = 0;
  int buflen = max(HEADBUF, NFIRSTSAMPLES * 2), len = 0;

  if (s->guessEncoding) {
    s->swap = 0;
  }
  if (s->tmpbuf != NULL) {
    ckfree((char *)s->tmpbuf);
  }
  if ((s->tmpbuf = (short *) ckalloc(buflen)) == NULL) {
    Tcl_AppendResult(interp, "Could not allocate buffer!", NULL);
    return TCL_ERROR;
  }
  if (obj == NULL) {
    ch = Tcl_OpenFileChannel(interp, s->fcname, "r", 0);
    if (ch != NULL) {
      Tcl_SetChannelOption(interp, ch, "-translation", "binary");
#ifdef TCL_81_API
      Tcl_SetChannelOption(interp, ch, "-encoding", "binary");
#endif
      if ((len = Tcl_Read(ch, (char *)s->tmpbuf, buflen)) > 0) {
	Tcl_Close(interp, ch);
	ch = NULL;
      }
    } else {
      ckfree((char *)s->tmpbuf);
      s->tmpbuf = NULL;
      return TCL_ERROR;
    }
  } else {
    unsigned char *ptr = NULL;

    if (useOldObjAPI) {
      len = min(obj->length, buflen);
2958
2959
2960
2961
2962
2963
2964

2965
2966
2967
2968
2969
2970
2971
2972

2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989


2990
2991
2992
2993
2994
2995
2996


2997
2998
2999
3000
3001
3002
3003
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113

3114
3115

3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129

3130
3131
3132
3133
3134
3135
3136
3137

3138
3139
3140
3141
3142
3143
3144
3145
3146







+







-
+

-














-
+
+






-
+
+







  }
  s->firstNRead = len;

  for (ff = snackFileFormats; ff != NULL; ff = ff->nextPtr) {
    if (strcmp(s->fileType, ff->name) == 0) {
      if (obj == NULL) {
	status = SnackOpenFile(ff->openProc, s, interp, &ch, "r");
	if (status == TCL_OK) openedOk = 1;
      }
      if (status == TCL_OK) {
	status = (ff->getHeaderProc)(s, interp, ch, obj, (char *)s->tmpbuf);
      }
      if (strcmp(s->fileType, RAW_STRING) == 0 && s->guessEncoding) {
	GuessEncoding(s, (unsigned char *)s->tmpbuf, len);
      }
      if (obj == NULL && status == TCL_OK) {
      if (obj == NULL && openedOk == 1) {
	status = SnackCloseFile(ff->closeProc, s, interp, &ch);
	/*	Tcl_Close(interp, ch);*/
      }
      ckfree((char *)s->tmpbuf);
      s->tmpbuf = NULL;

      return(status);
    }
  }
  ckfree((char *)s->tmpbuf);
  s->tmpbuf = NULL;

  return TCL_OK;
}

int
PutHeader(Sound *s, Tcl_Interp *interp, int length)
PutHeader(Sound *s, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[],
	  int length)
{
  Snack_FileFormat *ff;

  for (ff = snackFileFormats; ff != NULL; ff = ff->nextPtr) {
    if (strcmp(s->fileType, ff->name) == 0) {
      if (ff->putHeaderProc != NULL) {
	return (ff->putHeaderProc)(s, interp, s->rwchan, NULL, length);
	return (ff->putHeaderProc)(s, interp, s->rwchan, NULL, objc, objv,
				   length);
      }
      break;
    }
  }
  return 0;
}

3059
3060
3061
3062
3063
3064
3065
3066
3067


3068
3069

3070
3071
3072
3073
3074
3075
3076
3077







3078
3079
3080
3081
3082
3083
3084
3085
3086
3087

3088
3089
3090
3091
3092
3093
3094
3202
3203
3204
3205
3206
3207
3208


3209
3210
3211

3212
3213







3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238







-
-
+
+

-
+

-
-
-
-
-
-
-
+
+
+
+
+
+
+










+







		    writeSamplesProc *writeProc, seekProc *seekProc)
{
  Snack_FileFormat *ff = (Snack_FileFormat *)ckalloc(sizeof(Snack_FileFormat));

  if (ff == NULL) {
    return TCL_ERROR;
  }
  ff->name = name;
  ff->guessProc  = guessProc;
  ff->name          = name;
  ff->guessProc     = guessProc;
  ff->getHeaderProc = getHeadProc;
  ff->extProc    = extProc;
  ff->extProc       = extProc;
  ff->putHeaderProc = putHeadProc;
  ff->openProc   = openProc;
  ff->closeProc  = closeProc;
  ff->readProc   = readProc;
  ff->writeProc  = writeProc;
  ff->seekProc   = seekProc;
  ff->nextPtr    = snackFileFormats;
  snackFileFormats = ff;
  ff->openProc      = openProc;
  ff->closeProc     = closeProc;
  ff->readProc      = readProc;
  ff->writeProc     = writeProc;
  ff->seekProc      = seekProc;
  ff->nextPtr       = snackFileFormats;
  snackFileFormats  = ff;

  return TCL_OK;
}

Snack_FileFormat snackRawFormat = {
  RAW_STRING,
  GuessRawFile,
  GetRawHeader,
  NULL,
  PutRawHeader,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  (Snack_FileFormat *) NULL
3102
3103
3104
3105
3106
3107
3108

3109
3110
3111
3112
3113
3114
3115
3116
3117

3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137

3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153


3154
3155
3156
3157
3158
3159
3160
3161
3162

3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182

3183
3184
3185
3186
3187
3188
3189
3190
3191
3192

3193
3194
3195
3196
3197
3198
3199
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299

3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350







+









+




















+















-
+
+









+




















+










+







  NULL,
  OpenMP3File,
  CloseMP3File,
  ReadMP3Samples,
  NULL,
  SeekMP3File,
  FreeMP3Header,
  ConfigMP3Header,
  (Snack_FileFormat *) NULL
};

Snack_FileFormat snackSmpFormat = {
  SMP_STRING,
  GuessSmpFile,
  GetSmpHeader,
  ExtSmpFile,
  PutSmpHeader,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  (Snack_FileFormat *) NULL
};

Snack_FileFormat snackCslFormat = {
  CSL_STRING,
  GuessCslFile,
  GetCslHeader,
  ExtCslFile,
  PutCslHeader,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  (Snack_FileFormat *) NULL
};

Snack_FileFormat snackSdFormat = {
  SD_STRING,
  GuessSdFile,
  GetSdHeader,
  ExtSdFile,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  FreeSdHeader,
  ConfigSdHeader,
  (Snack_FileFormat *) NULL
};

Snack_FileFormat snackAiffFormat = {
  AIFF_STRING,
  GuessAiffFile,
  GetAiffHeader,
  ExtAiffFile,
  PutAiffHeader,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  (Snack_FileFormat *) NULL
};

Snack_FileFormat snackAuFormat = {
  AU_STRING,
  GuessAuFile,
  GetAuHeader,
  ExtAuFile,
  PutAuHeader,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  (Snack_FileFormat *) NULL
};

Snack_FileFormat snackWavFormat = {
  WAV_STRING,
  GuessWavFile,
  GetWavHeader,
  ExtWavFile,
  PutWavHeader,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  (Snack_FileFormat *) NULL
3407
3408
3409
3410
3411
3412
3413
3414

3415
3416
3417

3418
3558
3559
3560
3561
3562
3563
3564

3565
3566
3567

3568
3569







-
+


-
+

    }
    infoPtr->filePos = index;

    return(infoPtr->buffer[pos]);
  }
}

SnackFileFormat *
Snack_FileFormat *
Snack_GetFileFormats()
{
  return (SnackFileFormat *) snackFileFormats;
  return snackFileFormats;
}

Changes to snack/generic/jkSoundProc.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
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
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







-
+

+
+




+
+
+
+
+
-
+
+



+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+




+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+















-
+
+


-
+
+

+
+
+
+







    Tcl_AppendResult(interp, str, NULL);
  }
  Tcl_AppendResult(interp, "}", NULL);
  return TCL_ERROR;
}

int
CheckWinlen(Tcl_Interp *interp, int winlen)
CheckWinlen(Tcl_Interp *interp, int winlen, int fftlen)
{
  char str[10];

  if (winlen < 1) {
    Tcl_AppendResult(interp, "-winlength must be > 0", NULL);
    return TCL_ERROR;
  }
  if (winlen > fftlen) {
    Tcl_AppendResult(interp, "-winlength must be <= fftlength (", NULL);
    sprintf(str, "%d)", fftlen);
    Tcl_AppendResult(interp, str, NULL);
    return TCL_ERROR;
  
  }

  return TCL_OK;
}

void
GetFloatMonoSig(Sound *s,SnackLinkedFileInfo *info,
		float *sig, int beg, int len, int channel) {
  /* sig buffer must be allocated, file must be open! */

  int i;

  if (s->storeType == SOUND_IN_MEMORY) {
    if (s->nchannels == 1 || channel != -1) {
      int p = beg * s->nchannels + channel;

      for (i = 0; i < len; i++) {
	sig[i] = (float) (FSAMPLE(s, p));
	p += s->nchannels;
      }
    } else {
      int c;

      for (i = 0; i < len; i++) {
	sig[i] = 0.0;
      }
      for (c = 0; c < s->nchannels; c++) {
	int p = beg * s->nchannels + c;
	  
	for (i = 0; i < len; i++) {
	  sig[i] += (float) (FSAMPLE(s, p));
	  p += s->nchannels;
	}
      }
      for (i = 0; i < len; i++) {
	sig[i] /= s->nchannels;
      }
    }
  } else { /* storeType != SOUND_IN_MEMORY */
    if (s->nchannels == 1 || channel != -1) {
      int p = beg * s->nchannels + channel;

      for (i = 0; i < len; i++) {
	sig[i] = (float) (GetSample(info, p));
	p += s->nchannels;
      }
    } else {
      int c;
	
      for (i = 0; i < len; i++) {
	sig[i] = 0.0;
      }
      for (c = 0; c < s->nchannels; c++) {
	int p = beg * s->nchannels + c;
	  
	for (i = 0; i < len; i++) {
	  sig[i] += (float) (GetSample(info, p));
	  p += s->nchannels;
	}
      }
      for (i = 0; i < len; i++) {
	sig[i] /= s->nchannels;
      }
    }
  }
}

static float xfft[NMAX];
static float ffts[NMAX];
static float hamwin[NMAX];
#define SNACK_DEFAULT_DBPWINTYPE SNACK_WIN_HAMMING
#define SNACK_DEFAULT_DBP_LPC_ORDER 20
#define SNACK_MAX_LPC_ORDER  40

int
CheckLPCorder(Tcl_Interp *interp, int lpcorder)
{
  char str[10];
  if (lpcorder < 1) {
    Tcl_AppendResult(interp, "-lpcorder must be > 0", NULL);
    return TCL_ERROR;
  }
  if (lpcorder > SNACK_MAX_LPC_ORDER) {
    Tcl_AppendResult(interp, "-lpcorder must be <= ", NULL);
    sprintf(str, "%d)", SNACK_MAX_LPC_ORDER);
    Tcl_AppendResult(interp, str, NULL);
    return TCL_ERROR;
  }
  
  return TCL_OK;
}

int
dBPowerSpectrumCmd(Sound *s, Tcl_Interp *interp, int objc,
		   Tcl_Obj *CONST objv[])
{
  double dpreemph = 0.0;
  float preemph = 0.0;
  int i, j, n = 0, arg;
  int channel = 0, winlen = 256, fftlen = 512;
  int startpos = 0, endpos = -1, skip = -1;
  Tcl_Obj *list;
  SnackLinkedFileInfo info;
  SnackWindowType wintype = SNACK_DEFAULT_DBPWINTYPE;
  static char *subOptionStrings[] = {
    "-start", "-end", "-channel", "-fftlength", "-winlength", "-windowlength",
    "-preemphasisfactor", "-skip", "-windowtype", NULL
    "-preemphasisfactor", "-skip", "-windowtype", "-analysistype",
    "-lpcorder", NULL
  };
  enum subOptions {
    START, END, CHANNEL, FFTLEN, WINLEN, WINDOWLEN, PREEMPH, SKIP, WINTYPE
    START, END, CHANNEL, FFTLEN, WINLEN, WINDOWLEN, PREEMPH, SKIP, WINTYPE,
    ANATYPE, LPCORDER
  };
  float *sig_lpc;
  float presample = 0.0;
  int siglen, type = 0, lpcOrder = SNACK_DEFAULT_DBP_LPC_ORDER;
  float g_lpc;

  if (s->debug > 0) Snack_WriteLog("Enter dBPowerSpectrumCmd\n");

  for (arg = 2; arg < objc; arg += 2) {
    int index;
	
    if (Tcl_GetIndexFromObj(interp, objv[arg], subOptionStrings,
180
181
182
183
184
185
186























187
188
189
190
191
192

193
194
195
196
197
198
199
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310

311
312
313
314
315
316
317
318







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+





-
+







    case WINTYPE:
      {
	char *str = Tcl_GetStringFromObj(objv[arg+1], NULL);
	if (GetWindowType(interp, str, &wintype) != TCL_OK)
	  return TCL_ERROR;
	break;
      }
    case ANATYPE:
      {
	int len;
 	char *str = Tcl_GetStringFromObj(objv[arg+1], &len);
	
	if (strncasecmp(str, "lpc", len) == 0) {
	  type = 1;
	} else if (strncasecmp(str, "fft", len) == 0) {
	  type = 0;
	} else {
	  Tcl_AppendResult(interp, "-type should be FFT or LPC", (char *)NULL);
	  return TCL_ERROR;
	}
	break;
      }
    case LPCORDER:
      {
	if (Tcl_GetIntFromObj(interp, objv[arg+1], &lpcOrder) != TCL_OK)
	  return TCL_ERROR;
	if (CheckLPCorder(interp, lpcOrder) != TCL_OK)
	  return TCL_ERROR;
	break;
      }
    }
  }

  if (CheckFFTlen(interp, fftlen) != TCL_OK) return TCL_ERROR;

  if (CheckWinlen(interp, winlen) != TCL_OK) return TCL_ERROR;
  if (CheckWinlen(interp, winlen, fftlen) != TCL_OK) return TCL_ERROR;

  preemph = (float) dpreemph;

  if (startpos < 0 || startpos > s->length - fftlen) {
    Tcl_AppendResult(interp, "FFT window out of bounds", NULL);
    return TCL_ERROR;
  }
219
220
221
222
223
224
225
226


227
228
229
230
231
232
233
234
235
236
237
238
239
240
241



242
243
244
245

246
247
248

249
250
251




252
253
254
255


256
257
258

259
260

261
262

263
264


265
266
267
268
269
270
271
272


273
274
275

276
277
278
279
280
281




282
283
284
285

286
287
288
289
290
291
292
293
294
295



296
297
298
299
300







































































301


302
303
304
305
306
307
308
338
339
340
341
342
343
344

345
346
347
348
349
350
351
352
353
354







355
356
357




358



359



360
361
362
363




364
365



366


367


368


369
370




371



372
373



374






375
376
377
378




379










380
381
382


383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456

457
458
459
460
461
462
463
464
465







-
+
+








-
-
-
-
-
-
-
+
+
+
-
-
-
-
+
-
-
-
+
-
-
-
+
+
+
+
-
-
-
-
+
+
-
-
-
+
-
-
+
-
-
+
-
-
+
+
-
-
-
-

-
-
-
+
+
-
-
-
+
-
-
-
-
-
-
+
+
+
+
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-



+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+







  Snack_InitWindow(hamwin, winlen, fftlen, wintype);

  Snack_InitFFT(fftlen);

  if (skip < 1) {
    skip = fftlen;
  }
  n = (endpos - startpos) / skip;
  siglen = endpos - startpos;
  n = siglen / skip;
  if (n < 1) {
    n = 1;
  }

  if (s->nchannels == 1) {
    channel = 0;
  }

  for (j = 0; j < n; j++) {
    if (s->storeType == SOUND_IN_MEMORY) {
      if (s->nchannels == 1 || channel != -1) {
	int p = (startpos + j * skip) * s->nchannels + channel;

	for (i = 0; i < fftlen; i++) {
	  xfft[i] = (float) ((FSAMPLE(s, p + s->nchannels)
  if (type != 0 && n > 0) { /* LPC + FFT */
    if (siglen < fftlen) siglen = fftlen;
    sig_lpc = (float *) ckalloc(siglen * sizeof(float));
			      - preemph * FSAMPLE(s, p))
			     * hamwin[i]);
	    p += s->nchannels;
	}

      } else {
	int c;
	
    GetFloatMonoSig(s, &info, sig_lpc, startpos, siglen, channel);
	for (i = 0; i < fftlen; i++) {
	  xfft[i] = 0.0;
	}
    if (startpos > 0)
      GetFloatMonoSig(s, &info, &presample, startpos - 1, 1, channel);
    PreEmphase(sig_lpc, presample, siglen, preemph);

	for (c = 0; c < s->nchannels; c++) {
	  int p = (startpos + j * skip) * s->nchannels + c;
	  
	  for (i = 0; i < fftlen; i++) {
    /* windowing signal to make lpc look more like the fft spectrum ??? */
    for (i = 0; i < winlen/2; i++) {
	    xfft[i] += (float) ((FSAMPLE(s, p + s->nchannels)
				 - preemph * FSAMPLE(s, p))
				* hamwin[i]);
      sig_lpc[i] = sig_lpc[i] * hamwin[i];
	    p += s->nchannels;
	  }
    }
	}
	for (i = 0; i < fftlen; i++) {
    for (i = winlen/2; i < winlen; i++) {
	  xfft[i] /= s->nchannels;
	}
      sig_lpc[i + siglen - winlen] = sig_lpc[i + siglen - winlen] * hamwin[i];
    }
      }
    } else { /* storeType != SOUND_IN_MEMORY */
      if (s->nchannels == 1 || channel != -1) {
	int p = (startpos + j * skip) * s->nchannels + channel;

	for (i = 0; i < fftlen; i++) {
	  xfft[i] = (float) ((GetSample(&info, p + s->nchannels)
			      - preemph * GetSample(&info, p))
    g_lpc = LpcAnalysis(sig_lpc, siglen, xfft, lpcOrder);
    ckfree((char *) sig_lpc);
			     * hamwin[i]);
	  p += s->nchannels;
	}

      } else {
	int c;
	
	for (i = 0; i < fftlen; i++) {
	  xfft[i] = 0.0;
	}
    for (i = 0; i <= lpcOrder; i++) {
      /* the factor is a guess, try looking for analytical value */
      xfft[i] = xfft[i] * 5000000000.0f;
    }
	for (c = 0; c < s->nchannels; c++) {
	  int p = (startpos + j * skip) * s->nchannels + c;
	  
	  for (i = 0; i < fftlen; i++) {
    for (i = lpcOrder + 1; i < fftlen; i++) {
	    xfft[i] += (float) ((GetSample(&info, p + s->nchannels)
				 - preemph * GetSample(&info, p))
				* hamwin[i]);
	    p += s->nchannels;
	  }
	}
	for (i = 0; i < fftlen; i++) {
	  xfft[i] /= s->nchannels;
	}
      }
      xfft[i] = 0.0;
    }
    
    }

    Snack_DBPowerSpectrum(xfft);
    
    for (i = 0; i < fftlen/2; i++) {
      ffts[i] = -xfft[i];
    }

  } else {  /* usual FFT */

    for (j = 0; j < n; j++) {
      if (s->storeType == SOUND_IN_MEMORY) {
	if (s->nchannels == 1 || channel != -1) {
	  int p = (startpos + j * skip) * s->nchannels + channel;
	  
	  for (i = 0; i < fftlen; i++) {
	    xfft[i] = (float) ((FSAMPLE(s, p + s->nchannels)
				- preemph * FSAMPLE(s, p))
			       * hamwin[i]);
	    p += s->nchannels;
	  }
	} else {
	  int c;
	  
	  for (i = 0; i < fftlen; i++) {
	    xfft[i] = 0.0;
	  }
	  for (c = 0; c < s->nchannels; c++) {
	    int p = (startpos + j * skip) * s->nchannels + c;
	    
	    for (i = 0; i < fftlen; i++) {
	      xfft[i] += (float) ((FSAMPLE(s, p + s->nchannels)
				   - preemph * FSAMPLE(s, p))
				  * hamwin[i]);
	      p += s->nchannels;
	    }
	  }
	  for (i = 0; i < fftlen; i++) {
	    xfft[i] /= s->nchannels;
	  }
	}
      } else { /* storeType != SOUND_IN_MEMORY */
	if (s->nchannels == 1 || channel != -1) {
	  int p = (startpos + j * skip) * s->nchannels + channel;
	  
	  for (i = 0; i < fftlen; i++) {
	    xfft[i] = (float) ((GetSample(&info, p + s->nchannels)
				- preemph * GetSample(&info, p))
			       * hamwin[i]);
	    p += s->nchannels;
	  }
	} else {
	  int c;
	  
	  for (i = 0; i < fftlen; i++) {
	    xfft[i] = 0.0;
	  }
	  for (c = 0; c < s->nchannels; c++) {
	    int p = (startpos + j * skip) * s->nchannels + c;
	    
	    for (i = 0; i < fftlen; i++) {
	      xfft[i] += (float) ((GetSample(&info, p + s->nchannels)
				   - preemph * GetSample(&info, p))
				  * hamwin[i]);
	      p += s->nchannels;
	    }
	  }
	  for (i = 0; i < fftlen; i++) {
	    xfft[i] /= s->nchannels;
	  }
	}
      }
      
      Snack_DBPowerSpectrum(xfft);
      
      for (i = 0; i < fftlen/2; i++) {
      ffts[i] += xfft[i];
	ffts[i] += xfft[i];
      }
    }
  }

  if (s->storeType != SOUND_IN_MEMORY) {
    CloseLinkedFile(&info);
  }

372
373
374
375
376
377
378
379
380































































































































































































































































































































































529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888









+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    Tcl_AppendResult(interp, "-windowtype must be hanning, hamming, bartlett,"
		     "blackman, or rectangle", NULL);
    return TCL_ERROR;
  }
  
  *wintype = type;

  return TCL_OK;
}

float  
LpcAnalysis (float *data, int N, float *f, int order) {
   int    i,m;
   float  sumU = 0.0;
   float  sumD = 0.0;
   float  b[SNACK_MAX_LPC_ORDER+1];
   float KK;

   float ParcorCoeffs[SNACK_MAX_LPC_ORDER];
   /* PreData should be used when signal is not windowed */
   float PreData[SNACK_MAX_LPC_ORDER];
   float *errF;
   float *errB;
   float errF_m = 0.0;

   if ((order < 1) || (order > SNACK_MAX_LPC_ORDER))  return 0.0f;

   errF = (float *) ckalloc((N+SNACK_MAX_LPC_ORDER) * sizeof(float));
   errB = (float *) ckalloc((N+SNACK_MAX_LPC_ORDER) * sizeof(float));

   for (i=0; i<order; i++) {
     ParcorCoeffs[i] = 0.0;
     PreData[i] = 0.0; /* delete here and use as argument when sig not windowed */
   };

   for (m=0; m<order; m++)
     errF[m] = PreData[m];
   for (m=0; m<N; m++)
     errF[m+order] = data[m] ;

   errB[0] = 0.0;
   for (m=1; m<N+order; m++)
     errB[m] = errF[m-1];

   for (i=0; i<order; i++) {

     sumU=0.0;
     sumD=0.0;
     for (m=i+1; m<N+order; m++) {
       sumU -= errF[m] * errB[m];
       sumD += errF[m] * errF[m] + errB[m] * errB[m];
     };

     if (sumD != 0) KK = 2.0f * sumU / sumD;   
     else KK = 0;
     ParcorCoeffs[i] = KK;


     for (m=N+order-1; m>i; m--) {
       errF[m] += KK * errB[m];
       errB[m] = errB[m-1] + KK * errF[m-1];
     };
   };

   for (i=order; i<N+order; i++) {
     errF_m += errF[i]*errF[i];
   }
   errF_m /= N;

   ckfree((char *)errF);
   ckfree((char *)errB);

   /* convert to direct filter coefficients */
   f[0] = 1.0;    
   for (m=1; m<=order; m++) {
     f[m] = ParcorCoeffs[m-1];
     for (i=1; i<m; i++)
       b[i] = f[i];
     for (i=1; i<m; i++)
       f[i] = b[i] + ParcorCoeffs[m-1] * b[m-i];
   }

   return (float)sqrt(errF_m);
}


void PreEmphase(float *sig, float presample, int len, float preemph) {
  int i;
  float temp;

  if (preemph == 0.0)  return;

  for (i = 0; i < len; i++) {
    temp = sig[i];
    sig[i] = temp - preemph * presample;
    presample = temp;
  }
}

#define SNACK_DEFAULT_POWERWINTYPE SNACK_WIN_HAMMING
#define DB 4.34294481903251830000000 /*  = 10 / ln(10)  */

int
powerCmd(Sound *s, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
  double dpreemph = 0.0, dscale = 1.0, dframelen = -1.0;
  float preemph = 0.0, scale = 1.0;
  int i, j, n = 0;
  int channel = 0, winlen = 256;
  int arg, startpos = 0, endpos = -1, framelen;
  float *powers = NULL;
  Tcl_Obj *list;
  SnackLinkedFileInfo info;
  SnackWindowType wintype = SNACK_DEFAULT_POWERWINTYPE;
  static char *subOptionStrings[] = {
    "-start", "-end", "-channel", "-framelength", "-windowlength",
    "-windowtype", "-preemphasisfactor", "-scale", "-progress", NULL
  };
  enum subOptions {
    START, END, CHANNEL, FRAMELEN, WINDOWLEN, WINTYPE, PREEMPH, SCALE,
    PROGRESS
  };

  if (s->debug > 0) { Snack_WriteLog("Enter powerCmd\n"); }

  if (s->cmdPtr != NULL) {
    Tcl_DecrRefCount(s->cmdPtr);
    s->cmdPtr = NULL;
  }

  for (arg = 2; arg < objc; arg += 2) {
    int index;
	
    if (Tcl_GetIndexFromObj(interp, objv[arg], subOptionStrings,
			    "option", 0, &index) != TCL_OK) {
      return TCL_ERROR;
    }

    if (arg + 1 == objc) {
      Tcl_AppendResult(interp, "No argument given for ",
		       subOptionStrings[index], " option", (char *) NULL);
      return TCL_ERROR;
    }
    
    switch ((enum subOptions) index) {
    case START:
      {
	if (Tcl_GetIntFromObj(interp, objv[arg+1], &startpos) != TCL_OK)
	  return TCL_ERROR;
	break;
      }
    case END:
      {
	if (Tcl_GetIntFromObj(interp, objv[arg+1], &endpos) != TCL_OK)
	  return TCL_ERROR;
	break;
      }
    case CHANNEL:
      {
	char *str = Tcl_GetStringFromObj(objv[arg+1], NULL);
	if (GetChannel(interp, str, s->nchannels, &channel) != TCL_OK) {
	  return TCL_ERROR;
	}
	break;
      }
    case FRAMELEN:
      {
	if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &dframelen) != TCL_OK)
	  return TCL_ERROR;
	break;
      }
    case WINDOWLEN:
      {
	if (Tcl_GetIntFromObj(interp, objv[arg+1], &winlen) != TCL_OK)
	  return TCL_ERROR;
	break;
      }
    case WINTYPE:
      {
	char *str = Tcl_GetStringFromObj(objv[arg+1], NULL);
	if (GetWindowType(interp, str, &wintype) != TCL_OK)
	  return TCL_ERROR;
	break;
      }
    case PREEMPH:
      {
	if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &dpreemph) != TCL_OK)
	  return TCL_ERROR;
	break;
      }
    case SCALE:
      {
	if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &dscale) != TCL_OK)
	  return TCL_ERROR;
	break;
      }
    case PROGRESS:
      {
	char *str = Tcl_GetStringFromObj(objv[arg+1], NULL);
	
	if (strlen(str) > 0) {
	  Tcl_IncrRefCount(objv[arg+1]);
	  s->cmdPtr = objv[arg+1];
	}
	break;
      }
    }
  } 

  if (winlen < 1) {
    Tcl_AppendResult(interp, "-windowlength must be > 0", NULL);
    return TCL_ERROR;
  }
  if (winlen > NMAX) {
    char str[10];

    sprintf(str, "%d", NMAX);
    Tcl_AppendResult(interp, "-windowlength must be <= ", str, NULL);
    return TCL_ERROR;
  }
  
  preemph = (float) dpreemph;
  scale   = (float) dscale;
  
  if (startpos < 0) startpos = 0;
  if (endpos >= (s->length - 1) || endpos == -1)
    endpos = s->length - 1;
  if (startpos > endpos) return TCL_OK;

  if (s->storeType != SOUND_IN_MEMORY) {
    if (OpenLinkedFile(s, &info) != TCL_OK) {
      return TCL_OK;
    }
  }

  Snack_InitWindow(hamwin, winlen, winlen, wintype);

  if (dframelen == -1.0) {
    dframelen = 0.01;
  }
  framelen = (int) (dframelen * s->samprate);
  n = (endpos - startpos - winlen / 2) / framelen + 1;
  if (n < 1) {
    n = 1;
  }
  if (s->nchannels == 1) {
    channel = 0;
  }

  powers = (float *) ckalloc(sizeof(float) * n);

  Snack_ProgressCallback(s->cmdPtr, interp, "Computing power", 0.0);

  for (j = 0; j < n; j++) {
    float power;
    int winstart = 0;
    if (s->storeType == SOUND_IN_MEMORY) {
      if (s->nchannels == 1 || channel != -1) {
	int p = (startpos + j * framelen - winlen/2) * s->nchannels + channel;

	if (p < 0) p = 0;
	if (p < winlen / 2) winstart = winlen / 2 - p;	
	for (i = winstart; i < winlen; i++) {
	  xfft[i] = (float) ((FSAMPLE(s, p + s->nchannels)
			      - preemph * FSAMPLE(s, p))
			     * hamwin[i]);
	  p += s->nchannels;
	}
      } else {
	int c;
	
	for (i = 0; i < winlen; i++) {
	  xfft[i] = 0.0;
	}
	for (c = 0; c < s->nchannels; c++) {
	  int p = (startpos + j * framelen - winlen/2) * s->nchannels + c;
	  
	  if (p < 0) p = 0;
	  if (p < winlen / 2) winstart = winlen / 2 - p;	
	  for (i = winstart; i < winlen; i++) {
	    xfft[i] += (float) ((FSAMPLE(s, p + s->nchannels)
				 - preemph * FSAMPLE(s, p))
				* hamwin[i]);
	    p += s->nchannels;
	  }
	}
	for (i = 0; i < winlen; i++) {
	  xfft[i] /= s->nchannels;
	}
      }
    } else { /* storeType != SOUND_IN_MEMORY */
      if (s->nchannels == 1 || channel != -1) {
	int p = (startpos + j * framelen - winlen/2) * s->nchannels + channel;
	
	if (p < 0) p = 0;
	if (p < winlen / 2) winstart = winlen / 2 - p;	
	for (i = winstart; i < winlen; i++) {
	  xfft[i] = (float) ((GetSample(&info, p + s->nchannels)
			      - preemph * GetSample(&info, p))
			     * hamwin[i]);
	  p += s->nchannels;
	}
      } else {
	int c;
	
	for (i = 0; i < winlen; i++) {
	  xfft[i] = 0.0;
	}
	for (c = 0; c < s->nchannels; c++) {
	  int p = (startpos + j * framelen - winlen/2) * s->nchannels + c;
	  
	  if (p < 0) p = 0;
	  if (p < winlen / 2) winstart = winlen / 2 - p;	
	  for (i = winstart; i < winlen; i++) {
	    xfft[i] += (float) ((GetSample(&info, p + s->nchannels)
				 - preemph * GetSample(&info, p))
				* hamwin[i]);
	    p += s->nchannels;
	  }
	}
	for (i = 0; i < winlen; i++) {
	  xfft[i] /= s->nchannels;
	}
      }
    }

    power = 0.0f;
    for (i = winstart; i < winlen; i++) {
      power += xfft[i] * xfft[i];
    }
    if (power < 1.0) power = 1.0;
    powers[j] = (float) (DB * log(scale * power / (float)(winlen - winstart)));

    if ((j % 10000) == 9999) {
      int res = Snack_ProgressCallback(s->cmdPtr, interp, "Computing power", 
				       (double) j / n);
      if (res != TCL_OK) {
	ckfree((char *) powers);
	return TCL_ERROR;
      }
    }
  }

  Snack_ProgressCallback(s->cmdPtr, interp, "Computing power", 1.0);

  list = Tcl_NewListObj(0, NULL);
  for (i = 0; i < n; i++) {
    Tcl_ListObjAppendElement(interp,list, Tcl_NewDoubleObj((double)powers[i]));
  }
  Tcl_SetObjResult(interp, list);

  if (s->storeType != SOUND_IN_MEMORY) {
    CloseLinkedFile(&info);
  }
  ckfree((char *) powers);

  if (s->debug > 0) { Snack_WriteLog("Exit powerCmd\n"); }

  return TCL_OK;
}

Changes to snack/generic/jkSynthesis.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 2001 Jonas Beskow <beskow@speech.kth.se>
 * Copyright (C) 2001-2002 Jonas Beskow <beskow@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
309
310
311
312
313
314
315
316

317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335


336
337
338
339
340
341






342
343
344
345
346
347
348


349

350



351
352
353
354
355
356
357


358

359
360
361
362
363
364
365









366
367
368
369
370
371
372


373
374
375
376

377
378
379
380
381







382
383
384
385
386
387
388
389


390
391
392
393
394
395
396

397
398




399
400






401
402
403
404
405
406
407
309
310
311
312
313
314
315

316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334

335
336
337
338
339



340
341
342
343
344
345
346
347
348
349
350


351
352
353
354

355
356
357
358
359
360
361
362


363
364
365
366







367
368
369
370
371
372
373
374
375
376
377
378
379
380


381
382
383
384
385
386
387





388
389
390
391
392
393
394
395
396
397
398
399
400


401
402
403
404
405
406
407
408
409
410


411
412
413
414
415

416
417
418
419
420
421
422
423
424
425
426
427
428







-
+


















-
+
+



-
-
-
+
+
+
+
+
+





-
-
+
+

+
-
+
+
+





-
-
+
+

+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+





-
-
+
+




+
-
-
-
-
-
+
+
+
+
+
+
+






-
-
+
+







+
-
-
+
+
+
+

-
+
+
+
+
+
+







}

static int
generatorFlowProc(Snack_Filter f, Snack_StreamInfo si, float *in, float *out,
		  int *inFrames, int *outFrames) {
  
  generatorFilter_t mf = (generatorFilter_t) f;
  int i,i0,i1,ii;
  int i, i0, i1, ii, fr, wi;
  double y = 1.0/RAND_MAX, z = 1.0/(*outFrames), ph = mf->_phase;
  double frac,a,b,v[2],tmp;
  
  /*  fprintf(stderr,"entering generatorFlowProc, *inFrames = %d\t*outFrames = %d, in = %p, out = %p\n",*inFrames,*outFrames,in,out); */
  
  if (mf->ntot>0 && mf->ngen + (*outFrames) > mf->ntot) {
    *outFrames = mf->ntot - mf->ngen;
  }
  
  /* read input samples (if any) - this is used by the SAMPLED wave type*/
  for (i=0;i<*inFrames;i++) {
    ii = i+mf->nSamples;
    if (ii>=MAX_SAMPLES) break;
    tmp = mf->samples[ii] = in[i];
    if (fabs(tmp) > mf->maxval) { mf->maxval = (float) fabs(tmp);}
  }
  mf->nSamples += i;
  *inFrames = i;
  

  i = 0;
  switch (mf->type) {
  case NOISE:
    
    for (i=0;i<*outFrames;i++) {
      frac = i*z;
      out[i]=(float)(LIN(mf->ampl,frac)*2*(y*rand()-.5));
    for (fr = 0; fr < *outFrames; fr++) {
      frac = fr*z;
      for (wi = 0; wi < si->outWidth; wi++) {
	out[i++]=(float)(LIN(mf->ampl,frac)*2*(y*rand()-.5));
      }
      i += (si->streamWidth - si->outWidth);
    }
    *inFrames = 0;
    break;

  case RECTANGLE:
    for (i=0;i<*outFrames;i++) {
      frac = i*z;
    for (fr = 0; fr < *outFrames; fr++) {
      frac = fr*z;
      ph = fmod (ph + LIN(mf->freq,frac)/si->rate,1.0);
      for (wi = 0; wi < si->outWidth; wi++) {
      out[i] = (float)(LIN(mf->ampl,frac)*(ph<LIN(mf->shape,frac)?-1:1));
	out[i++] = (float)(LIN(mf->ampl,frac)*(ph<LIN(mf->shape,frac)?-1:1));
      }
      i += (si->streamWidth - si->outWidth);
    }
    *inFrames = 0;
    break;

  case TRIANGLE:
    for (i=0;i<*outFrames;i++) {
      frac = i*z;
    for (fr = 0; fr < *outFrames; fr++) {
      frac = fr*z;
      ph = fmod (ph + LIN(mf->freq,frac)/si->rate,1.0);
      for (wi = 0; wi < si->outWidth; wi++) {
      if (ph < LIN(mf->shape,frac)) {
	out[i] = (float)(LIN(mf->ampl,frac)*(-1+2*(ph)/LIN(mf->shape,frac)));
      } else if (ph > LIN(mf->shape,frac)) {
	out[i] = (float)(LIN(mf->ampl,frac)*(1-2*(ph-LIN(mf->shape,frac))/(1-LIN(mf->shape,frac))));
      } else {
	out[i] = (float)LIN(mf->ampl,frac);
      }
	if (ph < LIN(mf->shape,frac)) {
	  out[i++] = (float)(LIN(mf->ampl,frac)*(-1+2*(ph)/LIN(mf->shape,frac)));
	} else if (ph > LIN(mf->shape,frac)) {
	  out[i++] = (float)(LIN(mf->ampl,frac)*(1-2*(ph-LIN(mf->shape,frac))/(1-LIN(mf->shape,frac))));
	} else {
	  out[i++] = (float)LIN(mf->ampl,frac);
	}
      }
      i += (si->streamWidth - si->outWidth);
    }
    *inFrames = 0;
    break;

  case SINE:
    for (i=0;i<*outFrames;i++) {
      frac = i*z;
    for (fr = 0; fr < *outFrames; fr++) {
      frac = fr*z;
      ph = fmod (ph + LIN(mf->freq,frac)/si->rate,1.0);
      a = sin(ph * 2 * M_PI);
      b = 2*LIN(mf->shape,frac)-1;
      a = a>b?a:b;
      for (wi = 0; wi < si->outWidth; wi++) {
      if (1-b==0.0) {
	out[i] = 0.0;
      } else {
	out[i] = (float)(LIN(mf->ampl,frac)*(a-.5-.5*b)/(1-b));
      }
	if (1-b==0.0) {
	  out[i++] = 0.0;
	} else {
	  out[i++] = (float)(LIN(mf->ampl,frac)*(a-.5-.5*b)/(1-b));
	}
      }
      i += (si->streamWidth - si->outWidth);
      *inFrames = 0;
    }
    break;

  case SAMPLED:
    if (mf->nSamples > 0) {
      for (i=0;i<*outFrames;i++) {
	frac = i*z;
      for (fr = 0; fr < *outFrames; fr++) {
	frac = fr*z;
	ph = fmod (ph + LIN(mf->freq,frac)/si->rate,1.0);
	a = ph*(mf->nSamples);
	i0 = (int)floor(a);
	i1 = (int)ceil(a)%mf->nSamples;
	v[0] = mf->samples[i0];
	v[1] = mf->samples[i1];
	frac = (a-i0);
	for (wi = 0; wi < si->outWidth; wi++) {
	out[i] = (float)(LIN(v,frac)*LIN(mf->ampl,frac)/mf->maxval);
      }
	  out[i++] = (float)(LIN(v,frac)*LIN(mf->ampl,frac)/mf->maxval);
	}
	i += (si->streamWidth - si->outWidth);
      }
    } else {
      for (i=0;i<*outFrames;i++) out[i] = 0;
      for (fr = 0; fr < *outFrames; fr++) {
	for (wi = 0; wi < si->outWidth; wi++) {
	  out[i++] = 0;
	}
	i += (si->streamWidth - si->outWidth);
      }
    }
  }
  mf->_phase = ph; /* save current phase value */
  mf->freq[0] = mf->freq[1];
  mf->ampl[0] = mf->ampl[1];
  mf->shape[0] = mf->shape[1];

Changes to snack/generic/shape.c.

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
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







-
-
+
+





+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+






+
+
+






-
+







#include <math.h>
#include "snack.h"

extern int littleEndian;
extern int useOldObjAPI;

typedef struct {
   short max;
   short min;
  short max;
  short min;
} Maxmin;

/* --------------------------------------------------------------------- */

static short GetShortSample(Sound *s, long i, int c) {
  short res = 0;
   if (i >= Snack_GetLength(s) || s->storeType == SOUND_IN_CHANNEL)
      return 0;
   i = i * Snack_GetNumChannels(s) + c;
   if (s->storeType == SOUND_IN_MEMORY) {
     return (short) FSAMPLE(s, i);
   } else {
      if (s->linkInfo.linkCh == NULL) {
 	 OpenLinkedFile(s, &s->linkInfo);
      }
 	 return (short) GetSample(&s->linkInfo, i);
   }
   return 0;
  if (i >= Snack_GetLength(s) || s->storeType == SOUND_IN_CHANNEL)
    return 0;
  i = i * Snack_GetNumChannels(s) + c;
  if (s->storeType == SOUND_IN_MEMORY) {
    res = (short) FSAMPLE(s, i);
  } else {
    if (s->linkInfo.linkCh == NULL) {
      OpenLinkedFile(s, &s->linkInfo);
    }
    res = (short) GetSample(&s->linkInfo, i);
  }
  if (Snack_GetSampleEncoding(s) == LIN8) {
    res <<= 8;
  }
  return res;
}

static void SetShortSample(Sound *s, long i, int c, short val) {
  if (i >= Snack_GetLength(s) || s->storeType != SOUND_IN_MEMORY)
    return;
  i = i * Snack_GetNumChannels(s) + c;
  if (Snack_GetSampleEncoding(s) == LIN8) {
    val /= 256;
  }
  FSAMPLE(s, i) = (float) val;
}

/* --------------------------------------------------------------------- */

int shapeCmd(Sound *s, Tcl_Interp *interp, int objc,
	     Tcl_Obj *CONST objv[])
             Tcl_Obj *CONST objv[])
{
  int arg, width = 0, pps = 0, startpos = 0, endpos = -1, check = 0;
  int byteOrder = SNACK_NATIVE;
  int encoding, sampsize;
  Sound *shp = NULL, *preshp = NULL;
  long k0, k1;
  int i, c, first, nc, nbytes = 0, mn, mx;
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
236
237
238
239
240
241



242
243
244


245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263

264
265
266
267
268
269

270
271
272
273


274
275
276
277
278
279
280
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
236
237
238
239
240
241
242
243
244
245
246
247



248
249
250
251


252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271

272
273
274
275
276
277

278
279
280


281
282
283
284
285
286
287
288
289







-
+
+


-
+










-
-
+
+



-
-
-
-
-
+
+
+
+
+

-
-
-
-
-
+
+
+
+
+

-
-
-
-
-
+
+
+
+
+

+
-
-
-
-
-
+
+
+
+
+

-
-
-
-
-
+
+
+
+
+

















-
-
+
+



-
-
-
-
-
+
+
+
+
+

-
-
-
-
-
+
+
+
+
+

-
-
-
-
-
+
+
+
+
+

-
-
-
-
-
+
+
+
+
+

-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+



















-
+


-
-
+
+




-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+




-
-
-
+
+
+

-
-
+
+


















-
+





-
+


-
-
+
+







    }
  }

  if (shp) {

    /* Store shape into sound */
    static char *subOptionStrings[] = {
      "-start", "-end", "-pixelspersecond", "-format", "-check", NULL
      "-start", "-end", "-pixelspersecond", "-format", "-encoding", "-check",
      NULL
    };
    enum subOptions {
      START, END, PPS, FORMAT, CHECK
      START, END, PPS, FORMAT, ENCODING, CHECK
    };
    int index;
      
    /* default values for the sound target case */
    pps = 100;
    encoding = Snack_GetSampleEncoding(s);
    sampsize = Snack_GetBytesPerSample(s);

    for (arg = 3; arg < objc; arg += 2) {
      if (Tcl_GetIndexFromObj(interp, objv[arg], subOptionStrings,
			      "option", 0, &index) != TCL_OK) {
	return TCL_ERROR;
                              "option", 0, &index) != TCL_OK) {
        return TCL_ERROR;
      }
      switch ((enum subOptions) index) {
      case START:
	{
	  if (Tcl_GetIntFromObj(interp, objv[arg+1], &startpos) != TCL_OK)
	    return TCL_ERROR;
	  break;
	}
        {
          if (Tcl_GetIntFromObj(interp, objv[arg+1], &startpos) != TCL_OK)
            return TCL_ERROR;
          break;
        }
      case END:
	{
	  if (Tcl_GetIntFromObj(interp, objv[arg+1], &endpos) != TCL_OK)
	    return TCL_ERROR;
	  break;
	}
        {
          if (Tcl_GetIntFromObj(interp, objv[arg+1], &endpos) != TCL_OK)
            return TCL_ERROR;
          break;
        }
      case PPS:
	{
	  if (Tcl_GetIntFromObj(interp, objv[arg+1], &pps) != TCL_OK)
	    return TCL_ERROR;
	  break;
	}
        {
          if (Tcl_GetIntFromObj(interp, objv[arg+1], &pps) != TCL_OK)
            return TCL_ERROR;
          break;
        }
      case FORMAT:
      case ENCODING:
	{
	  if (GetEncoding(interp, objv[arg+1], &encoding, &sampsize) != TCL_OK)
	    return TCL_ERROR;
	  break;
	}
        {
          if (GetEncoding(interp, objv[arg+1], &encoding, &sampsize) != TCL_OK)
            return TCL_ERROR;
          break;
        }
      case CHECK:
	{
	  if (Tcl_GetBooleanFromObj(interp, objv[arg+1], &check) != TCL_OK)
	    return TCL_ERROR;
	  break;
	}
        {
          if (Tcl_GetBooleanFromObj(interp, objv[arg+1], &check) != TCL_OK)
            return TCL_ERROR;
          break;
        }
      }
    }
  } else {

    /* Return shape as binary data */
    static char *subOptionStrings[] = {
      "-start", "-end", "-width", "-pixelspersecond",
      "-shape", "-byteorder", NULL
    };
    enum subOptions {
      START, END, WIDTH, PPS, SHAPE, BYTEORDER
    };
    int index;
    
    for (arg = 2; arg < objc; arg += 2) {

      if (Tcl_GetIndexFromObj(interp, objv[arg], subOptionStrings,
			      "option", 0, &index) != TCL_OK) {
	return TCL_ERROR;
                              "option", 0, &index) != TCL_OK) {
        return TCL_ERROR;
      }
      switch ((enum subOptions) index) {
      case START:
	{
	  if (Tcl_GetIntFromObj(interp, objv[arg+1], &startpos) != TCL_OK)
	    return TCL_ERROR;
	  break;
	}
        {
          if (Tcl_GetIntFromObj(interp, objv[arg+1], &startpos) != TCL_OK)
            return TCL_ERROR;
          break;
        }
      case END:
	{
	  if (Tcl_GetIntFromObj(interp, objv[arg+1], &endpos) != TCL_OK)
	    return TCL_ERROR;
	  break;
	}
        {
          if (Tcl_GetIntFromObj(interp, objv[arg+1], &endpos) != TCL_OK)
            return TCL_ERROR;
          break;
        }
      case WIDTH:
	{
	  if (Tcl_GetIntFromObj(interp, objv[arg+1], &width) != TCL_OK)
	    return TCL_ERROR;
	  break;
	}
        {
          if (Tcl_GetIntFromObj(interp, objv[arg+1], &width) != TCL_OK)
            return TCL_ERROR;
          break;
        }
      case PPS:
	{
	  if (Tcl_GetIntFromObj(interp, objv[arg+1], &pps) != TCL_OK)
	    return TCL_ERROR;
	  break;
	}
        {
          if (Tcl_GetIntFromObj(interp, objv[arg+1], &pps) != TCL_OK)
            return TCL_ERROR;
          break;
        }
      case SHAPE:
	{
	  int nchar = 0;
	  char *str = Tcl_GetStringFromObj(objv[arg+1], &nchar);
	  if (nchar > 0 && (preshp = Snack_GetSound(interp, str)) == NULL) {
	    return TCL_ERROR;
	  }
	  break;
	}
        {
          int nchar = 0;
          char *str = Tcl_GetStringFromObj(objv[arg+1], &nchar);
          if (nchar > 0 && (preshp = Snack_GetSound(interp, str)) == NULL) {
            return TCL_ERROR;
          }
          break;
        }
      case BYTEORDER:
	{
	  int length;
	  char *str = Tcl_GetStringFromObj(objv[arg+1], &length);
	  
	  if (strncasecmp(str, "littleEndian", length) == 0) {
	    byteOrder = SNACK_LITTLEENDIAN;
	  } else if (strncasecmp(str, "bigEndian", length) == 0) {
	    byteOrder = SNACK_BIGENDIAN;
	  } else {
	    Tcl_AppendResult(interp, "-byteorder option should be bigEndian or littleEndian", NULL);
	    return TCL_ERROR;
	  }
	  break;
	}
        {
          int length;
          char *str = Tcl_GetStringFromObj(objv[arg+1], &length);
          
          if (strncasecmp(str, "littleEndian", length) == 0) {
            byteOrder = SNACK_LITTLEENDIAN;
          } else if (strncasecmp(str, "bigEndian", length) == 0) {
            byteOrder = SNACK_BIGENDIAN;
          } else {
            Tcl_AppendResult(interp, "-byteorder option should be bigEndian or littleEndian", NULL);
            return TCL_ERROR;
          }
          break;
        }
      }
    }
  }

  /* Characteristics of 'shaped' sound */
  nc = Snack_GetNumChannels(s);
  Fe = Snack_GetSampleRate(s);

  /* Adjust boundaries to fit the sound and satisfy the constraint: */
  /*    len = (endpos-startpos+1)/Fe = width/pps */
  if (startpos < 0) startpos = 0;
  if (width > 0 && pps > 0) {
    endpos = startpos + (int) (Fe * width / (float) pps - 1);
  }
  if (/* endpos >= (Snack_GetLength(s) - 1) || */ endpos == -1)
    endpos = Snack_GetLength(s) - 1;
  begin = (double) startpos / Fe;
  len = (double) (endpos - startpos + 1) / Fe;
  if (width <= 0 && pps > 0) {
     width = (int) ceil(len * pps);
    width = (int) ceil(len * pps);
  }
  if (width <= 0 || len <= 0) {
     Tcl_SetResult(interp, "Bad boundaries for shape", TCL_STATIC);
     return TCL_ERROR;
    Tcl_SetResult(interp, "Bad boundaries for shape", TCL_STATIC);
    return TCL_ERROR;
  }

  /* Only checks if existing shape seems compatible with sound then exits */
  if (shp && check) {
     float shpLen = (float) Snack_GetLength(shp) / Snack_GetSampleRate(shp);
     if (Snack_GetNumChannels(shp) == 2 * nc
	 && fabs(len - shpLen) < 0.05 * len
	 && Snack_GetSampleRate(shp) < 1000) {
	Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
     } else {
	Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
     }
     return TCL_OK;
    float shpLen = (float) Snack_GetLength(shp) / Snack_GetSampleRate(shp);
    if (Snack_GetNumChannels(shp) == nc
	&& fabs(len - shpLen) < 0.05 * len
	&& Snack_GetSampleRate(shp) < 2000) {
      Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
    } else {
      Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
    }
    return TCL_OK;
  }

  /* Try to use precomputed shape instead of original sound */
  if (preshp != NULL
      && Snack_GetNumChannels(preshp) == 2 * nc
      && Snack_GetSampleRate(preshp) * len / width > 2.0) {
     Fe = Snack_GetSampleRate(preshp);
      && Snack_GetNumChannels(preshp) == nc
      && Snack_GetSampleRate(preshp) * len / width > 4) {
    Fe = Snack_GetSampleRate(preshp) / 2;
  } else {
     Fe = Snack_GetSampleRate(s);
     preshp = NULL;
    Fe = Snack_GetSampleRate(s);
    preshp = NULL;
  }

  /* number of samples per point */
  if (pps > 0) {
    hRatio = Fe / pps;
  } else {
    hRatio = Fe * len / width;
  }

  /* round first sample to be a multiple of hRatio */
  /* in order to avoid distortions during scrolling */
  pos = floor(begin * Fe / hRatio) * hRatio;

  if (shp) {

    /* update shape parameters and get free space into sound target */
    Tcl_Obj *empty = Tcl_NewStringObj("",-1);
    if (Snack_GetSoundWriteStatus(shp) != IDLE &&
	Snack_GetSoundReadStatus(shp) != IDLE) {
        Snack_GetSoundReadStatus(shp) != IDLE) {
      Snack_StopSound(shp, interp);
    }
    SetFcname(shp, interp, empty);
    Tcl_DecrRefCount(empty);
    shp->storeType = SOUND_IN_MEMORY;
    Snack_SetSampleRate(shp, pps);
    Snack_SetSampleRate(shp, 2 * pps);
    Snack_SetSampleEncoding(shp, encoding);
    Snack_SetBytesPerSample(shp, sampsize);
    Snack_SetNumChannels(shp, 2 * nc);
    Snack_SetLength(shp, (int) ceil((endpos+1-pos)/hRatio));
    Snack_SetNumChannels(shp, nc);
    Snack_SetLength(shp, (int) (2 * ceil((endpos+1-pos)/hRatio)));
    if (Snack_ResizeSoundStorage(shp, Snack_GetLength(shp)) != TCL_OK) {
      return TCL_ERROR;
    }

  } else {

    /* Get memory for binary shape */
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326































327
328
329
330
331
332
333
334
335
336
337
338
339


340
341
342
343
344


345
346
347
348
349
350
351
352
353
354
355
356

357
358
359
360
361
362
363
364
365
366
367

368
369
370

371
372
373
374
375

376
377
378
379
380
381
382
383



384
385
386
387
388
389



390
391
392
393
394


395
396
397
398
399
400
401
402
403
404









405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423

424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439

440
441
442
443
444

445
446
447
448
449
450
451
452
298
299
300
301
302
303
304































305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346


347
348
349
350
351


352
353
354
355
356
357
358
359
360
361
362
363
364

365
366
367
368
369
370
371
372
373
374
375

376
377
378

379
380
381
382
383

384
385
386
387
388
389



390
391
392
393
394
395



396
397
398
399
400
401


402
403
404









405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431

432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447

448
449
450
451
452

453
454
455
456
457
458
459
460
461







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+











-
-
+
+



-
-
+
+











-
+










-
+


-
+




-
+





-
-
-
+
+
+



-
-
-
+
+
+



-
-
+
+

-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+


















-
+















-
+




-
+








#endif
    }
  }

  /* compute min/max for each point */
  q = (Maxmin *) Tcl_Alloc(sizeof(Maxmin) * nc);
  for (i=0; i<width; i++) {
     k0 = (long) pos; pos += hRatio; k1 = (long) pos;
     first = 1;
     while (k0 < k1 && k0 <= endpos) {
       for (c=0; c<nc; c++) {
	 if (preshp) {
	   mx = GetShortSample(preshp, k0, 2*c);
	   mn = GetShortSample(preshp, k0, 2*c+1);
	 } else {
	   mn = mx = GetShortSample(s, k0, c);
	 }
	 if (first || (mn < q[c].min))
	   q[c].min = mn; 
	 if (first || (mx > q[c].max))
	   q[c].max = mx; 
	 }
       first = 0;
       k0++;
     }
     if (first && k0 > endpos) break;
     if (shp) {
       for (c=0; c<nc; c++) {
	 SetShortSample(shp, i, 2*c,   q[c].max);
	 SetShortSample(shp, i, 2*c+1, q[c].min);
	 /* Snack_SetSample(shp, 2*c,   i, q[c].max);
	    Snack_SetSample(shp, 2*c+1, i, q[c].min); */
       }
     } else {
       for (c=0; c<nc; c++) {
	 p[c+i*nc] = q[c];
       }
     }
    k0 = (long) pos; pos += hRatio; k1 = (long) pos;
    first = 1;
    while (k0 < k1 && k0 <= endpos) {
      for (c=0; c<nc; c++) {
	if (preshp) {
	  mx = GetShortSample(preshp, 2*k0, c);
	  mn = GetShortSample(preshp, 2*k0+1, c);
	} else {
	  mn = mx = GetShortSample(s, k0, c);
	}
	if (first || (mn < q[c].min))
	  q[c].min = mn; 
	if (first || (mx > q[c].max))
	  q[c].max = mx; 
      }
      first = 0;
      k0++;
    }
    if (first && k0 > endpos) break;
    if (shp) {
      for (c=0; c<nc; c++) {
	SetShortSample(shp, 2*i,   c, q[c].max);
	SetShortSample(shp, 2*i+1, c, q[c].min);
	/* Snack_SetSample(shp, 2*c,   i, q[c].max);
	   Snack_SetSample(shp, 2*c+1, i, q[c].min); */
      }
    } else {
      for (c=0; c<nc; c++) {
	p[c+i*nc] = q[c];
      }
    }
  }
  Tcl_Free((char *)q);

  /* return result */
  if (shp) {
    Snack_UpdateExtremes(shp, 0, Snack_GetLength(shp), SNACK_NEW_SOUND);
  } else {

    /* Use correct byte order */
    if (littleEndian) {
      if (byteOrder == SNACK_BIGENDIAN) {
	for (i = 0; i < (int) (nbytes / sizeof(short)); i++)
	  ((short *)p)[i] = Snack_SwapShort(((short *)p)[i]);
        for (i = 0; i < (int) (nbytes / sizeof(short)); i++)
          ((short *)p)[i] = Snack_SwapShort(((short *)p)[i]);
      }
    } else {
      if (byteOrder == SNACK_LITTLEENDIAN) {
	for (i = 0; i < (int) (nbytes / sizeof(short)); i++)
	  ((short *)p)[i] = Snack_SwapShort(((short *)p)[i]);
        for (i = 0; i < (int) (nbytes / sizeof(short)); i++)
          ((short *)p)[i] = Snack_SwapShort(((short *)p)[i]);
      }
    }
    
    Tcl_SetObjResult( interp, resObj);
  }
  return TCL_OK;
}

/* --------------------------------------------------------------------- */

int dataSamplesCmd(Sound *s, Tcl_Interp *interp, int objc,
            Tcl_Obj *CONST objv[])
		   Tcl_Obj *CONST objv[])
{
  int arg, startpos = 0, endpos = -1;
  int byteOrder = SNACK_NATIVE;
  int pos, i, c, nbytes;
  Tcl_Obj *resObj = NULL;
  short *p = NULL;

  /* Get options */
  for (arg = 2; arg < objc; arg += 2) {
    static char *subOptionStrings[] = {
       "-start", "-end", "-byteorder",  NULL
      "-start", "-end", "-byteorder",  NULL
    };
    enum subOptions {
       START, END, BYTEORDER
      START, END, BYTEORDER
    };
    int index;

    if (Tcl_GetIndexFromObj(interp, objv[arg], subOptionStrings,
			    "option", 0, &index) != TCL_OK) {
                            "option", 0, &index) != TCL_OK) {
      return TCL_ERROR;
    }
    switch ((enum subOptions) index) {
    case START:
      {
	if (Tcl_GetIntFromObj(interp, objv[arg+1], &startpos) != TCL_OK)
	  return TCL_ERROR;
	break;
        if (Tcl_GetIntFromObj(interp, objv[arg+1], &startpos) != TCL_OK)
          return TCL_ERROR;
        break;
      }
    case END:
      {
	if (Tcl_GetIntFromObj(interp, objv[arg+1], &endpos) != TCL_OK)
	  return TCL_ERROR;
	break;
        if (Tcl_GetIntFromObj(interp, objv[arg+1], &endpos) != TCL_OK)
          return TCL_ERROR;
        break;
      }
    case BYTEORDER:
      {
	int length;
	char *str = Tcl_GetStringFromObj(objv[arg+1], &length);
        int length;
        char *str = Tcl_GetStringFromObj(objv[arg+1], &length);

	if (strncasecmp(str, "littleEndian", length) == 0) {
	   byteOrder = SNACK_LITTLEENDIAN;
	} else if (strncasecmp(str, "bigEndian", length) == 0) {
	   byteOrder = SNACK_BIGENDIAN;
	} else {
	  Tcl_AppendResult(interp, "-byteorder option should be bigEndian or littleEndian", NULL);
	  return TCL_ERROR;
	}
	break;
        if (strncasecmp(str, "littleEndian", length) == 0) {
	  byteOrder = SNACK_LITTLEENDIAN;
        } else if (strncasecmp(str, "bigEndian", length) == 0) {
	  byteOrder = SNACK_BIGENDIAN;
        } else {
          Tcl_AppendResult(interp, "-byteorder option should be bigEndian or littleEndian", NULL);
          return TCL_ERROR;
        }
        break;
      }
    }
  }
   
  /* Adjust boundaries */
  if (startpos < 0) startpos = 0;
  if (/* endpos >= (Snack_GetLength(s) - 1) || */ endpos == -1)
    endpos = Snack_GetLength(s) - 1;
  if (startpos > endpos) return TCL_OK;

  /* Get memory */
  resObj = Tcl_NewObj();
  nbytes = sizeof(short) * Snack_GetNumChannels(s) * (endpos - startpos + 1);
  if (useOldObjAPI) {
    Tcl_SetObjLength(resObj, nbytes);
    p = (short *) resObj->bytes;
  } else {
#ifdef TCL_81_API
     p = (short *) Tcl_SetByteArrayLength(resObj, nbytes);
    p = (short *) Tcl_SetByteArrayLength(resObj, nbytes);
#endif
  }

  /* Put samples into array as binary shorts */
  i = 0;
  for (pos = startpos; pos <= endpos; pos++) {
    for (c = 0; c < Snack_GetNumChannels(s); c++) {
      p[i++] = GetShortSample(s, pos, c);
    }
  }

  /* Use correct byte order */
  if (littleEndian) {
    if (byteOrder == SNACK_BIGENDIAN) {
      for (i = 0; i < (int) (nbytes / sizeof(short)); i++)
	p[i] = Snack_SwapShort(p[i]);
        p[i] = Snack_SwapShort(p[i]);
    }
  } else {
    if (byteOrder == SNACK_LITTLEENDIAN) {
      for (i = 0; i < (int) (nbytes / sizeof(short)); i++)
	p[i] = Snack_SwapShort(p[i]);
        p[i] = Snack_SwapShort(p[i]);
    }
  }

  Tcl_SetObjResult( interp, resObj);
  return TCL_OK;
}

/* --------------------------------------------------------------------- */

Changes to snack/generic/snack.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
18
19
20
21
22
23
24

25
26
27
28
29
30
31
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32







+







 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "snack.h"
#include "tk.h"
#include "jkCanvItems.h"
#include <string.h>

#if defined(__WIN32__)
#  define WIN32_LEAN_AND_MEAN
#  include <windows.h>
#  undef WIN32_LEAN_AND_MEAN

#ifdef __cplusplus
279
280
281
282
283
284
285
286

287
288
289

290
291
292

293
294
295

296
297
298

299
300
301
302


303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318

319
320

321
322

323
324
325
326
327
328
329
280
281
282
283
284
285
286

287
288
289

290
291
292

293
294
295

296
297
298

299
300
301


302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318

319
320

321
322

323
324
325
326
327
328
329
330







-
+


-
+


-
+


-
+


-
+


-
-
+
+















-
+

-
+

-
+







  }

  soundHashTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
  filterHashTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));

  Tcl_CreateObjCommand(interp, "sound", Snack_SoundCmd,
		       (ClientData) soundHashTable, (Tcl_CmdDeleteProc *)NULL);

  
  Tcl_CreateObjCommand(interp, "snack::sound", Snack_SoundCmd,
		       (ClientData) soundHashTable, Snack_SoundDeleteCmd);

  
  Tcl_CreateObjCommand(interp, "audio", Snack_AudioCmd,
		       NULL, (Tcl_CmdDeleteProc *)NULL);

  
  Tcl_CreateObjCommand(interp, "snack::audio", Snack_AudioCmd,
		       NULL, Snack_AudioDeleteCmd);

  
  Tcl_CreateObjCommand(interp, "snack::mixer", Snack_MixerCmd,
		       NULL, Snack_MixerDeleteCmd);

  
  Tcl_CreateObjCommand(interp, "snack::filter", Snack_FilterCmd,
		       (ClientData) filterHashTable, Snack_FilterDeleteCmd);

  Tcl_CreateObjCommand(interp, "snack::debug", 
  
  Tcl_CreateObjCommand(interp, "snack::debug",
		       (Tcl_ObjCmdProc*) Snack_DebugCmd,
		       NULL, (Tcl_CmdDeleteProc *)NULL);

  snackDebugChannel = Tcl_GetStdChannel(TCL_STDERR);
  debugInterp = interp;
  
  Tcl_SetVar(interp, "snack::patchLevel", SNACK_PATCH_LEVEL, TCL_GLOBAL_ONLY);
  Tcl_SetVar(interp, "snack::version",    SNACK_VERSION,     TCL_GLOBAL_ONLY);

  Tcl_InitHashTable(soundHashTable, TCL_STRING_KEYS);
  Tcl_InitHashTable(filterHashTable, TCL_STRING_KEYS);

  if (initialized == 0) {
    SnackDefineFileFormats(interp);
    SnackCreateFilterTypes(interp);

    
    SnackAudioInit();
      
    
    Tcl_CreateExitHandler(Snack_ExitProc, (ClientData) NULL);

    
    initialized = 1;
  }
#ifdef SNACK_CSLU_TOOLKIT
  Snack_AddSubCmd(SNACK_SOUND_CMD, "fromCSLUshWave",
		  (Snack_CmdProc *) fromCSLUshWaveCmd, NULL);
  Snack_AddSubCmd(SNACK_SOUND_CMD, "toCSLUshWave",
		  (Snack_CmdProc *) toCSLUshWaveCmd, NULL);

Changes to snack/generic/snack.h.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
25
26
27
28
29
30
31
32
33


25
26
27
28
29
30
31


32
33







-
-
+
+
# undef TCL_STORAGE_CLASS
# define TCL_STORAGE_CLASS DLLEXPORT
#endif

#include "jkSound.h"
#include "jkAudIO.h"

#define SNACK_VERSION     "2.0"
#define SNACK_PATCH_LEVEL "2.0.7"
#define SNACK_VERSION     "2.1"
#define SNACK_PATCH_LEVEL "2.1.6"

Changes to snack/generic/snackDecls.h.

91
92
93
94
95
96
97
98

99
100
101
102
103
104
105
91
92
93
94
95
96
97

98
99
100
101
102
103
104
105







-
+







				Sound * s, Tcl_Interp * interp, 
				Tcl_Channel * ch));
/* 22 */
EXTERN void		Snack_WriteLog _ANSI_ARGS_((char * s));
/* 23 */
EXTERN void		Snack_WriteLogInt _ANSI_ARGS_((char * s, int n));
/* 24 */
EXTERN SnackFileFormat * Snack_GetFileFormats _ANSI_ARGS_((void));
EXTERN Snack_FileFormat * Snack_GetFileFormats _ANSI_ARGS_((void));
/* 25 */
EXTERN void		Snack_InitWindow _ANSI_ARGS_((float * hamwin, 
				int winlen, int fftlen, int type));
/* 26 */
EXTERN int		Snack_InitFFT _ANSI_ARGS_((int n));
/* 27 */
EXTERN int		Snack_DBPowerSpectrum _ANSI_ARGS_((float * x));
145
146
147
148
149
150
151
152

153
154
155
156
157
158
159
145
146
147
148
149
150
151

152
153
154
155
156
157
158
159







-
+







    short (*snack_Mulaw2Lin) _ANSI_ARGS_((unsigned char u_val)); /* 17 */
    short (*snack_SwapShort) _ANSI_ARGS_((short s)); /* 18 */
    int (*snackSeekFile) _ANSI_ARGS_((seekProc * SeekProc, Sound * s, Tcl_Interp * interp, Tcl_Channel ch, int pos)); /* 19 */
    int (*snackOpenFile) _ANSI_ARGS_((openProc * OpenProc, Sound * s, Tcl_Interp * interp, Tcl_Channel * ch, char * mode)); /* 20 */
    int (*snackCloseFile) _ANSI_ARGS_((closeProc * CloseProc, Sound * s, Tcl_Interp * interp, Tcl_Channel * ch)); /* 21 */
    void (*snack_WriteLog) _ANSI_ARGS_((char * s)); /* 22 */
    void (*snack_WriteLogInt) _ANSI_ARGS_((char * s, int n)); /* 23 */
    SnackFileFormat * (*snack_GetFileFormats) _ANSI_ARGS_((void)); /* 24 */
    Snack_FileFormat * (*snack_GetFileFormats) _ANSI_ARGS_((void)); /* 24 */
    void (*snack_InitWindow) _ANSI_ARGS_((float * hamwin, int winlen, int fftlen, int type)); /* 25 */
    int (*snack_InitFFT) _ANSI_ARGS_((int n)); /* 26 */
    int (*snack_DBPowerSpectrum) _ANSI_ARGS_((float * x)); /* 27 */
    void (*snack_StopSound) _ANSI_ARGS_((Sound * s, Tcl_Interp * interp)); /* 28 */
    int (*snack_ProgressCallback) _ANSI_ARGS_((Tcl_Obj * cmd, Tcl_Interp * interp, char * type, double fraction)); /* 29 */
    void (*snack_CreateFileFormat) _ANSI_ARGS_((Snack_FileFormat * typePtr)); /* 30 */
    long (*snack_SwapLong) _ANSI_ARGS_((long s)); /* 31 */

Changes to snack/generic/sound.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
43
44
45
46
47
48
49








50
51
52
53
54
55
56
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64







+
+
+
+
+
+
+
+







BOOL APIENTRY
DllMain(HINSTANCE hInst, DWORD reason, LPVOID reserved)
{
  snackHInst = hInst;
  return TRUE;
}
#endif

#ifdef MAC
#include <string.h>
int main (void)
{
	return 0;
}
#endif

Tcl_Channel snackDebugChannel = NULL;
static Tcl_Interp *debugInterp = NULL;
int debugLevel = 0;
char *snackDumpFile = NULL;

int
83
84
85
86
87
88
89
90

91
92
93
94
95
96
97
91
92
93
94
95
96
97

98
99
100
101
102
103
104
105







-
+







      Tcl_AppendResult(interp, "can not open dump file in a safe interpreter",
		       (char *) NULL);
      return TCL_ERROR;
    }
    str = Tcl_GetStringFromObj(objv[3], &len);
    snackDumpFile = (char *) ckalloc(len + 1);
    strcpy(snackDumpFile, str);
   }
  }
  if (debugLevel > 0) {
    str = Tcl_GetVar(interp, "sound::patchLevel", TCL_GLOBAL_ONLY);
    Tcl_Write(snackDebugChannel, "Sound patch level: ", 19);
    Tcl_Write(snackDebugChannel, str, strlen(str));
    Tcl_Write(snackDebugChannel, "\n", 1);
    Tcl_Flush(snackDebugChannel);
  }
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
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







+
+
+

+
+
















-
+








-
+




















-
+








-
+








-
+


-
+


-
+






-
+











-
+







			   Tcl_Obj *CONST objv[]);
#endif

int useOldObjAPI = 0;
static int initialized = 0;
int littleEndian = 0;

#ifdef __cplusplus
extern "C" SnackStubs *snackStubs;
#else
extern SnackStubs *snackStubs;
#endif

extern Tcl_HashTable *filterHashTable;

#if defined(Tcl_InitHashTable) && defined(USE_TCL_STUBS)
#undef Tcl_InitHashTable
#define Tcl_InitHashTable (tclStubsPtr->tcl_InitHashTable)
#endif

int
Sound_Init(Tcl_Interp *interp)
{
  char *version;
  Tcl_HashTable *soundHashTable;
  union {
    char c[sizeof(short)];
    short s;
  } order;

  
#ifdef USE_TCL_STUBS
  if (Tcl_InitStubs(interp, "8", 0) == NULL) {
    return TCL_ERROR;
  }
#endif

  version = Tcl_GetVar(interp, "tcl_version",
		       (TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG));

  
  if (strcmp(version, "8.0") == 0) {
    useOldObjAPI = 1;
  }

#ifdef TCL_81_API
  if (Tcl_PkgProvideEx(interp, "sound", SNACK_VERSION,
		       (ClientData) &snackStubs) != TCL_OK) {
    return TCL_ERROR;
  }
#else
  if (Tcl_PkgProvide(interp, "sound", SNACK_VERSION) != TCL_OK) {
    return TCL_ERROR;
  }
#endif

  soundHashTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
  filterHashTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));

  Tcl_CreateObjCommand(interp, "sound", Snack_SoundCmd,
		       (ClientData) soundHashTable, (Tcl_CmdDeleteProc *)NULL);

  
  Tcl_CreateObjCommand(interp, "snack::sound", Snack_SoundCmd,
		       (ClientData) soundHashTable, (Tcl_CmdDeleteProc *)NULL);
  
  Tcl_CreateObjCommand(interp, "sound::sound", Snack_SoundCmd,
		       (ClientData) soundHashTable, Snack_SoundDeleteCmd);
  
  Tcl_CreateObjCommand(interp, "audio", Snack_AudioCmd,
		       NULL, (Tcl_CmdDeleteProc *)NULL);

  
  Tcl_CreateObjCommand(interp, "snack::audio", Snack_AudioCmd,
		       NULL, (Tcl_CmdDeleteProc *)NULL);
  
  Tcl_CreateObjCommand(interp, "sound::audio", Snack_AudioCmd,
		       NULL, Snack_AudioDeleteCmd);
  
  Tcl_CreateObjCommand(interp, "sound::mixer", Snack_MixerCmd,
		       NULL, Snack_MixerDeleteCmd);

  
  Tcl_CreateObjCommand(interp, "snack::mixer", Snack_MixerCmd,
		       NULL, Snack_MixerDeleteCmd);

  
  Tcl_CreateObjCommand(interp, "snack::filter", Snack_FilterCmd,
		       (ClientData) filterHashTable, Snack_FilterDeleteCmd);

  
  Tcl_CreateObjCommand(interp, "snack::debug",
		       (Tcl_ObjCmdProc*) Snack_DebugCmd,
		       NULL, (Tcl_CmdDeleteProc *)NULL);

  snackDebugChannel = Tcl_GetStdChannel(TCL_STDERR);
  debugInterp = interp;

  
  Tcl_SetVar(interp, "snack::patchLevel", SNACK_PATCH_LEVEL, TCL_GLOBAL_ONLY);
  Tcl_SetVar(interp, "snack::version",    SNACK_VERSION,     TCL_GLOBAL_ONLY);
  Tcl_SetVar(interp, "sound::patchLevel", SNACK_PATCH_LEVEL, TCL_GLOBAL_ONLY);
  Tcl_SetVar(interp, "sound::version",    SNACK_VERSION,     TCL_GLOBAL_ONLY);

  Tcl_InitHashTable(soundHashTable, TCL_STRING_KEYS);
  Tcl_InitHashTable(filterHashTable, TCL_STRING_KEYS);

  if (initialized == 0) {
    SnackDefineFileFormats(interp);
    SnackCreateFilterTypes(interp);

    
    SnackAudioInit();
    
    Tcl_CreateExitHandler(Snack_ExitProc, (ClientData) NULL);
    
    initialized = 1;
  }
#ifdef SNACK_CSLU_TOOLKIT

Changes to snack/mac/README.

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

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
-
+
+
+
+
+
+
+
+
+
+
+









-
-
-
-
-
-
-
-
-







In order to use Snack you will have to install Tcl/Tk 8.3 first.
In order to use Snack you will have to install Tcl/Tk 8.3.3 first.


Building Snack using Metrowerks CodeWarrior
-------------------------------------------------------------------
Use the CodeWarrior project file: snack.mcp.sit.hqx

You will have to specify the location of the Tcl/Tk include files
which are part of the Tcl/Tk source distribution.
This is the default compiler for the Snack Macintosh binaries.


Building Snack using MPW
-------------------------------------------------------------------
Snack can be compiled using Apple's free MPW compiler which can be
downloaded from http://developer.apple.com/tools/mpw-tools/

You will have to edit the makefile in order to specify the location of the
Tcl/Tk include files which are part of the Tcl/Tk source distribution.


Building Snack using Metrowerks CodeWarrior
-------------------------------------------------------------------
Building Snack using CodeWarrior is not as tested as with MPW.
Use the CodeWarrior project file: snack.mcp.sit.hqx

You will have to specify the location of the Tcl/Tk include files
which are part of the Tcl/Tk source distribution.


Installation
-------------------------------------------------------------------
You must put the file snack.shlb in the standard library location, 
i.e. the "Tool Command Language" folder within the Extensions folder. 

You have to give Tcl scripts ample memory. This is done by marking the

Changes to snack/mac/jkAudIO_mac.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/*
 * Copyright (C) 1998-2001
 * Copyright (C) 1998-2002
 * Dan Ellis
 * Leonid Spektor
 * Frederic Bonnet
 * Kåre Sjölander
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
1039
1040
1041
1042
1043
1044
1045






1046
1047
1048
1049
1050
1051
1052
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058







+
+
+
+
+
+







}

int
SnackAudioMaxNumberChannels(char *device)
{
  return(2);
}

int
SnackAudioMinNumberChannels(char *device)
{
  return(1);
}

void
SnackMixerGetInputJackLabels(char *buf, int n)
{
  OSErr oe;
  char *devname = NULL;	/* how to ask for default input device */
  long inRefNum;

Changes to snack/mac/snack.make.

33
34
35
36
37
38
39

40
41
42
43
44
45
46
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47







+







				  "{SrcDir}jkSoundFile.c" 
				  "{SrcDir}jkSoundProc.c" 
				  "{SrcDir}snack.c" 
				  "{SrcDir}jkFormatMP3.c" 
				  "{SrcDir}jkMixer.c" 
				  "{SrcDir}jkAudio.c" 
				  "{SrcDir}jkFilter.c" 
				  "{SrcDir}jkFilterIIR.c" 
				  "{SrcDir}jkSynthesis.c" 
				  "{SrcDir}shape.c" 
				  "{SrcDir}snackStubInit.c"
				  
#

### Object Files ###
59
60
61
62
63
64
65

66
67
68
69
70
71
72
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74







+







				  "{ObjDir}jkSoundFile.c.x" 
				  "{ObjDir}jkSoundProc.c.x" 
				  "{ObjDir}snack.c.x" 
				  "{ObjDir}jkFormatMP3.c.x" 
				  "{ObjDir}jkMixer.c.x" 
				  "{ObjDir}jkAudio.c.x" 
				  "{ObjDir}jkFilter.c.x" 
				  "{ObjDir}jkFilterIIR.c.x" 
				  "{ObjDir}jkSynthesis.c.x" 
				  "{ObjDir}shape.c.x" 
				  "{ObjDir}snackStubInit.c.x"

### Libraries ###

LibFiles-PPC    =  
118
119
120
121
122
123
124

125
126
127
128
129
130
131
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134







+







"{ObjDir}jkSoundEdit.c.x"  Ÿ  "{SrcDir}jkSoundEdit.c"
"{ObjDir}jkSoundFile.c.x"  Ÿ  "{SrcDir}jkSoundFile.c"
"{ObjDir}jkSoundProc.c.x"  Ÿ  "{SrcDir}jkSoundProc.c"
"{ObjDir}snack.c.x"  Ÿ  "{SrcDir}snack.c"
"{ObjDir}jkFormatMP3.c.x"  Ÿ  "{SrcDir}jkFormatMP3.c"
"{ObjDir}jkAudio.c.x"  Ÿ  "{SrcDir}jkAudio.c"
"{ObjDir}jkFilter.c.x"  Ÿ  "{SrcDir}jkFilter.c"
"{ObjDir}jkFilterIIR.c.x"  Ÿ  "{SrcDir}jkFilterIIR.c"
"{ObjDir}jkSynthesis.c.x"  Ÿ  "{SrcDir}jkSynthesis.c"
"{ObjDir}jkMixer.c.x"  Ÿ  "{SrcDir}jkMixer.c"
"{ObjDir}shape.c.x"  Ÿ  "{SrcDir}shape.c"
"{ObjDir}snackStubInit.c.x"  Ÿ  "{SrcDir}snackStubInit.c"


### Optional Dependencies ###

Changes to snack/mac/snack.mcp.sit.hqx.

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

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
236





237
238
239
240
241
242
243
244
245
246


247


-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
+
(This file must be converted with BinHex 4.0)

:$A0ZB@0V,QeMF#jcDA3!8dP84&0*9#%!!!!!*JF!!!&'5-06593K!!%!!#B(FNa
KG3)m!!!!&J2C!!d*FfjKBfXZE@0`'"S$f@rX!qeQSJ!!!!!!!!!!!q8e3&h,!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$rrrrr68e3FN0A588"!,CQ6d5feXQP!!!
!!!!"4qi!!!!!!!!PJ3!!')F!!!!!!!"ZZ3Ei+X,I#+Zc!H[b#1rBZSp`XYP&f#C
VA8EBCS35hKQlPGRE+92#eVMHpXQam"5IE'9i*Mi[J[pBP(pN2pPR6cMCNQH4`5D
$6@jlC*2M%8iQf`L2%Gj,EMrEj2L4iaHjr8CBK*-pP1b"(GNHi4Fj9K0l+9CiMke
GFSq`+rEE)q`lXT*00KPXF[[)J*000VP0"ZZqGC*0'mQphR5ECQP(@hMaJEHbNGm
jb8qZAC42LR81YRlD,mak*jYG9bCVBFZCakiV1hjp[2b-0mR,mmT*!mq&PfHphr(
&MPp2&R),*i2Pb'*+IL%,@FJY4hE!@!!"icZlcKUX[D@Ac10HR@N,@mJQ[mq1X!Z
!(%"!!(kH&ali[$J1(FHCjcL&*8lKA@FkKAHA('IqARc@&IS+A*e6'pIp-6G*JMJ
T9T0iTqpP(9pVbVN&["9F"Di'E`CAJQ[!YH$V`C[!A`*[!qm%l`+hUjB%ei-E`0Y
"DUi6h!4Z"VH![`bq$Y`+GS%8f"eJMFT2F"'i'*`29S0eB$hB!-i$&i+0i(*`"AJ
Gf!3Z!C["&V!9A!UfJGH#bm"fF!(B!9i2hJ$H#1D"B6!I,!!KJa"B#"D"aEBZK$Y
m#m"5X!`X"mH!Bm&ai(K`!MJ4V!$2!5H"Nm%!H#ji(RJq1!@m#*`'AJa1"b["9i1
AJ+m",`@RJKH#-m$,`-Y"i5eI2rJ,i"AJDm&I"+m%V`+["Um"Ci'[!QH$%A!11"G
m0rLli1I!Km$hJ!q!l`*r$h`[q$l`Gm!r"ImBI#IiDI$p)*cj+I$2`Gm(2`$q!IJ
Cm'(`Jq#(`#q!(`Br!RiHr#MiKq$(`)q$I`6q#IJJq!R`Nq"R`5q#Mi#2JKH!A`A
r#[aVm'r!Vi'2Jem'[`jq!raEm#r!Vi"2J(m*rKhi*2Mhi$I"I`$r%A`+I"Vm&[J
Bq#A`E[!Hm)hJVi!l`6hJ'm!hJEm+[KRF!Hi'pi,l`(["A`2hJlm1rJEi&[!h`EH
#E`-2J!I"qm$l`9hJfm(I!Ym"r[BKr[dfq%r3K(!4P'$XY6P,`Bf19)([i"4iJL"
`#&`&$m%$m!+F!$I!fI!&h!%[`!R`$3I1iQ9`#a`"2m#aj"NHJ92K$IJ8(Z(eF"(
F$,r#8I!MR!Dh`VI`2T`,plZm#eHM)G!@k!'AYq&LY!&mM1C`14N0!Gr#Th!D2!Y
R`VY`-a`*$m1TF$,e#Nr#VfJ*DJaqKPrK9(J%[S@Vi94d$C`29m2lm$@kJGT'ak"
Id"RS$h3!()kfF$8+h)X'FE8+'J@q4kHJDG!4k"9d%[S*lB1H3N1KRp""D#!d&,8
-Tk1(d%ES)IJ&rNCI`8&`%4b&eN*MSEI3&RD(3he5L`icG@XS1#'ZP9bG&0G)VVk
L6Z%9Z!Y1Fh8608RG*A86Y8`0`hY`QB[8[lhJS!e%+q@M18L[f2rA1H2VbSV[Gmp
1b`CVa$5LZ6rkk%0h6NprA&b51#6C#RIJXMNL2N%i([YFFB2JIESBU5IXZRGDKYj
E3Cp6))4IaeKiLR%JXMUSPqZficr[+C!!MhQ)5P$*N!!rjq5M4f*8J02"+m'V`+[
"Dm!)50lRJ[2!qH"#X"UX!4H"Lm%kX"jX!"["*V!&h!KZ"VH!AH"fF#HiLj+T!'H
$%A!15$dY!"H#e@!0@!XZ"Z[!HV!4E!+AJ-eJ#pJ+,J@hJ*hJ*T!!pqd'pi%(`)0
jRAEA4DNYM['9X@feb28Q0rKZh8r58XZ6E22+`bZNk-R,Aq,8QeKT5kV0VHCi9H0
j"hMRhq,'!rF)%&a&l&2qTYjG*jUPm-+bN4(TpaKae@qj5N+I%hlY5,E$6iV$`86
L*S%[mHZEpFmlGp3,jl`$kiD'9Akll(hhE$6rZ4AAQiX@XP%ffAZR[4qdphfcdI2
I8%em,fkfJY#[&fhPm5U00G[H+h5(204qRl9[YhFh-`IX2@,[FqapVVd[X2H&pPj
YlcAfAQ[[LqfpcYlVlEh4hT[XIBQp0pYlLlfhf[Y5HkGj)&RGGSmkDCRMb)RR"HH
KlX)C2S[TMS3DkFf3!'PAQ6l9N!#Q)(*Ka8mDIR'NrHqfr!*1GE8kR'FNY(CirEJ
h'G69kHqS9F[rV"GASjePr50m,9MS&0j8bqV&FV%F4fNFqXAbZXV+9C2&YF0U4Ef
BE9rKJq2Ufjip[#GUA&(BACMITdjE2-9dUCaFQZDP"H")KkPmSl[,,BGZQ[TTDDH
V2PRLh$K8,9E'VMBb`"55pB!PiNT`1lJ(h![Z"pmbbhV1bFql3Gf&hfhUeQm*iHl
NXhTcEDM$!N)"NA)lcH*QFC0r`r9a8Nq2"+Mf2$p0Le8hfh(8HlP,H@`Ve[`X#k,
'd3"e5+M+LYYU(A1[D3GK[6JiP5AZ8HqV9fh#[XCIldI(R"F&UBUjFb,dNf-4QS0
SmS5[qe[1SD+B@9kk&!mM!!m(GrcPljj0al*Uk(A*%Er',F@49KBdJaYIH"AN"00
XJ@a5cJ-*-plA9BiiLJTH@LXD%QYc)cmm%U,066dhI#RE'L#GlVDUP%9IQH+F+9-
Lp*FT[Qf$kiilpTH$1&HRc4-*AqEIq&+f1i*SLp,CllppeFSANiecIbVaG61QpmU
F(CZ$p&!1*AmCBLC!QTMa(L*Q!J`5-qjTBXClJ*KGjh6&Za'1P)RVHl5`69%-%R2
-2m98a[m`-H1A*QDm"iJjkMb3!,#Ma)aMPTJ*-86-AS"dZJH)fAA1P'Nr-EZq[F3
FGH`[Kc3aijdQCVb2%62q!m6X1[HR-Nl-M[-)%3p6m3JCjqKiQ*!!Xj3m5XSC@Xi
5mh&U2Nl1DASH*ZMRk(5%8%FS08ZUSl5D)GC"DXf5kc#p$K0X9ZJ-5je"XA1F[,2
dR5(`&bLF2ZF)MCX`@5Sh-Bl6Z3Nc61NQ5*E@6B`-Y8G$C&NR'QHJM+)4KNYTQ1U
p+)0-kN6TThcMRD9p%f18qNfJir3I$c1FZ)`-L)BB,FSK14#0N!#5"$(h6-eQTB'
*NC8(*ND1b%f8$*P(3f552N,U'F%5#c(k$"%Zh6p*p#Z(9*5%F%L&51U'9*4ZfC!
!LT&3$AdKeUGaC1Zplk%ErDQ6!H+k)adK`A$T-&VVk3"ZMIB9BEIQ1"BNbYap34c
&NA*1#)j8L$MR$%E)T$2$1)FN65T18Y%-4FQ@49c2T#1-&,ZRCY)"%$1$hN1eNj!
!-UN3#5@6#Y%MC&*"iMSQ(@%SfiQf[q0614HT9eqNSL6d45T%8PqNSR6VLe5-K,j
)KBL,Jh5%"&qN`fJ&T30N+kKE("`,%QA"[L#11%Jj*m4"+N4F(!a'b+66&3FTld2
L)"8R+3k'SQ6,)Li1dK&'LYd6"qN!L)0"lk(D5BL$9)L%1%L&k"%(U5"aFC!!MM#
8lH2L`(""XaXefQl$2ajMN6r4EM6iGpS4!2fm[lakXLaikD,B1jd2-VCib[2K3I%
BHK#mA4r'%p$,-'hLG6*8Hpa12,miQ[MmeTfYKfAYL-IdPidT,DRa6MHUUdb(iML
XQj9@EAi5RL`*UUFhcehkdEFUh4&12*pFcbmT%6hAK#ldr**Ld(2Y9S#HBd,fHAk
p"AA%9mR(Fie,a"khK&6Sm6e@)*jBl2&bD5YH0GfbX0Fc+RVLRSi!p$`1k5h215k
-HYck8hb8khVm$kABe89*Pd0C6bJJcbmKHqcY*rPAXQpGN!#N8SQh0IdSF`EF8Nc
R5ZDQ9!ie@h'5%@1*8kQ1(66AZ'%Bmfp"JaqfR-TBdBJT%kJ$f@(k59K&F2L3!#c
ad*($lcI2PBGXM-IL*+bA2+G5'bk@5e*dGHk5bi0YUqUAPXL(icGMk3ZH)RhP(R@
FH6#N+PCaePJLjUT#kp`q0(,9Z&jNI,Z6)c,+*#IT&#m1c0%#8+-@!&C(LIR'bb2
V1P9Jr'*&BB*UCRPa0004Df18qFPfer0R8ah2E$bUNdrA3r1C50jKPpKc'3I5mc,
AT9h29VpNE8NFb4k4$VrBc"MTFq-0eDh@`@FPAq!0+UPhQlkN0VjhqJP9i60rX'c
e@dQX*XMQa,&r[F4G)RrTbkHkpFPJh[120R4m!h2F&HN-()VBT,ThjbI93l8e%M&
C)69"P2Yj0@Xk&&lIS2GIahL2+0NBkZi'*9T!bGj16d1PTiX5Dc"f0mU6IHM$(HG
%'cAC4IBkU'jRf1Y4aRSG[AhGhLj,SVefU%XBkpl"if,eEGrZ8YDh[A2jFUiE*PH
hkd&m`0)iXUhTHVQeeSefeFK(c,M&Eh5-(HiZ2cHf"&0qNP[DJXcE8@k+-cC-NT9
0XjE&pF!ma&LTcTK9mXk,ZhDi,ANjhCh96MiUU+@k`Qff$RLeCqf*SFLq4"iKG1Q
B0LG00b1@pq"0$CUIdHGX0B5rV9iq5$Za4T*[B0CQ6&H8QPkVj%qe(%Cdc5UY-+l
,*cXQHHL1L1PHA8%UKAGiYT&@9*8Xe%aMjMI6h"T,'&DR9YECG1KpNHq&#NE1*&G
9m3%,,"$0SZ-9Xj*P8ED*,%[q+"`M%*IR0H4SaBjY4$0mfkjmVMEXAj85`'68d,(
61Sa+TTBaqc*jQ12U[U2@65ELb$aPQaG#hii+f-&6($XkMqaZ5b,26Ad[Vf[(G88
@K"KrFNl0T4UC-+A$K[arIe2CA2!6lip03')dD'+)dml!c$$c$N1FQPC[eF"9KSK
Dhdj,E@M`GAN2C41LGr&8+ib6Ir@r'j%fK"@*`fJj+pYap!HcKTNjl-jKGqF@Fq+
chpeClqlFBRHqZc[ERAR%$2pPEM%cMCP6b%aMAZR1,'BL-21+h6R&S#eJ$Ylc*km
c`G2bF[+0929[faE36PR[KR55I'"GiTUHqI'cFPZDZBiZ@emG)lKb'r,&A$U$b-e
m"hcKqGlTPYe`f"9c94l+E9AhhM'qF(VkYYrfJUPqLmYCHf!NUFF,VlrhJHdA6Nm
rerYKAVc0k4`93kH1%82QBJd33kG2B+pcCZ1Z*kk6*RGXbQpR6S"q!-VI"R#1c2C
0Rj'@U(HX-DSqcbNX22B(823`ZYIm[@"I12kjiFJ[F)EdSiSfMfaHA4NX$BjVQBM
$KedNR+D9A0clkI2MQ0D5BmMde&m9EY6K)T-J`F1$R(Y1kIm5#2mif'+f"*!!aN$
4c2q04aX$mT0JFqq(aX$r,IU`62[j'0Rq')85bPH!D6$0!$R2(TDZPSTq@*iC6T!
!2NGk'dGCJrIimr9Ec(mhE[,C"5EB5'090R[`K1B&R[EZB@mFXeQ"h0R6K[pm11b
QimT[pUpaGcjLAjh##ar2rHM&54@XNUKL&j[LqQ$q2[Ef+DQEE,)V%Im*FGKpL(q
#11`G92lFBrQZ0pm&adcXP-Q8jPMR3UdXj$q`U`mfrL-Dldbc4Bb[S(ep*X4j3,r
fc1(I*@+`4`rr(f&MMaljhmM%BjHH5Fl(P"ZrXM+jPHI'Vhf&q!m*'cX(Q8ePa-C
H4qH(M#83'rXAbAp+mpJaakmpMbiihcP2E8Ef)CTUIKE`DeHL5KiUrdljRm3QHpE
!hDEdG0qDJ2k0BXFHE1,[Zq4,fY$)ekFpK+CPULTIRhEPZAMHEEHJ,J+UZHR00'2
[Ri!fcT!!AAk#l%J8d0j%Vh'@0&RC)b$HBlFJBV-6dSciTKJf#'J(T-ZF1fjLMk!
!1a+ade#!AA`#ql'a3irmja98EE([%,5!ZK"rBf1r)E0SKYMB&B*D`dBqf*8)'la
"hV#a[a)FJSdpNYL(#"X-`4j&f2MAKMep$1h)K4f*X&%6["FE0F%14GM)%6X@B@1
()RBY`XEZ3GLaX5q3!1U&N!"f"9+k$e%ACKmKE1bSa#j#f0JV#Dl!aPj2F"dfYJ2
4GQ*)0F513YMBViNpKE#a6a0l#Q&M(bEU&0ZrF'%[)@cIjm)H50!TrmHTTXS6Ej%
hE1b6a)j)f+JpGN2#4[hSHLCjbM[FLieF`'RBf#f&(C'`X315lTU5"cqB2C'`S36
B&`NEh-EH50MBUiRGNE#aSa6l)f&M"bRf5-,'rP,XBB50[D'S,fa`#6XBB@0(+(J
!fc0Fi&KXrm&&Z-EBf*''r#!Pi(e9NQ(pkkGrGSHeEa*NM`dZd+C-@$9*,@1M(YM
V#"[[e"9"`YUELEfAX-',ZMG3@2Y(iBZ0AD%-SiS0r3(rBk2@U4GXl&6&[NRBf)0
+rbX)LjAC,`NE1d9TUbRm#bjQE4HaIBq,DVA`RlQ`5a0bLESR*pM3@fb)JSeGS*c
0KhaRL4rC'`SEpFe16YLS@e9bqFSl1cCKFrHV`XD190LaXBm@QJXE1f1CAS(Bf&H
,2BaX6DIJ`"BMeUdMDVKhd)aepD4Q3&P9MNaLd@D8,HldrJGSKIQe92j3rZR2d4V
rTcp(DrbIr4cYPV(cGi50jJ6S3MZl0&PJU'l#i[,)fX(&aF9V9iqZjYSf9"ipX!k
L*H@BI3AGhHUXFmFDYjUK2Hk%pYaLrclbBcZiqk!q#1fj@AmJfNk1&IE[%@pXXUh
Pf1Iq(V(Ep8prI0cp@Qm(0i,khlJjIZq50CTc`!`&YrI#E)4JZZ0Xr8I2[rNblq2
Ip@mlricRRE1kV[r[f@8kA'8G(,NcQb2IVFEkYjiC"`89aY6,rEr!`Qb,eNceDmj
'8F@2q0rGVjN&a4Qr#BU0q3-PQ15h(M0VSc41I@BYq,AVFeN3KV+aqh4jE8I-2r&
qc4FBXb'SmclrMl'0VF5lX!@8Zh(VrBai!Fh+')p*FK23A)!*0l)JJpLB,6!a$*5
EJ1Bl90Kic(3i*bZ2NVq!CKP-bX+Ya!TS*XAN)#U6'c2riYab&[+IIP#c8Fi,fcj
cLS1DGh&q1,r'Qi+Dcc"Pe'GV4Gmmc4DiB#h$D-A'(Y064a1A'3C"lAaGZ3"(X9%
h1ZmMU0fTQIFK-e5#Iq$qkVZR"TPG%0+B%2CUTJcjrjrj"pLBjm!X&Qc-%0!I6%,
kcjrGRE(aEcrl5f0M&S21q`JpaB@j!T5c[0IX*Sf0Gl,$0$EQB$",!j[N`ChhNDG
C"$V[)dplCHZmMcc0$Y"j(hQDID$c2[+HjD,c2X+DCk(c2X+DkD(c2X+D@D(c2X+
DXD$c2X,Dp9VRIB3eEd*&FPJlD1Zm$c0E3HGpj1[rHChhNDqj*$V[)eqc1h6H4ll
Q51LmMhcYQkhc2[+eBlI1qmMAI"DGpj'[@53klk0!FdpdhNH"DNcRI44SeSI1qbJ
3"qUmM`*aQ-ll+0"HhcV[Sd"lG1ZmMi*IFG&j(i@DHD(c2JT9BcV[Se#c2R6H4k(
Q51LmMd,9ZXll+03Hi$V[Se$lHHZmMm)RZ1LmMb,0Q0"j(dAL!Thh8D5mk,b2)['
fc[XS%QrT[)mLl5'Zmck+Y01hc[XSqLNARIG4V2V3H4r&iJkGpe'X0qZmMf*T$jh
h8D`pbAAH4l&f(GIq6l&QSqLmMa,P61GpP1K0qZYHLA+Umcj+p#DGpe'Lq4dklk0
%R+6c2NTqcNARIC4UrVM1qbJ96qQmMe,9Jmll+0@X$*hh8DTC16V[Se4cI(6H4qP
2Z1LmMc,aU(CZbe4E1ZqM6,@U[bb@b8IRIC4TcT(1qbL6jY"j(fADQecRIC4T(SV
1qbMAR(29EHAL)jhh86illk0FmhedhNHjpMrAH4rPQTHNmcl+08p(1qjM0&0Gjhf
-%FqbQcNfkK0pK!erjU0JBfpeCX0JBqi*r)Q0'8a`KCbaiJ"f0XH'PQ"hFfc`&cZ
FBk01i%CXc!1#jl&4"q33fhHiX11jR((kQjCGcl'KHBL*$Dk%!l&4UmbU`FClQ0Q
$$3h%I#CX$)DLlV!aGiEpd1@-epakpN6(KUl3IG((LpI3DpLS*ACiamD-*l320V3
#Fh'`83ISBMN6T"(K0fcS(c3Q0MM'c"`6'lA+,"CXa',H$$BQa&&Vf1!YhLYRSQS
,(B%0[3FRBi1rd5rBi$,d-MCUKRhKXE%M2"S+'lU@rH'ar6FAY)1F#[8!L)-0r82
YB)-hf5XH'h@V@a&Ak'h`$$Bd"r1ZX+%[f6GHcMQU!rD1aiEHBqpiE'J-pSr("XH
alc`fkJSH`!EAXK-p0ZS![5aRNVTLc&[#KSk&jl&4@qa"M`hHBNi20[,,@l!aMdN
Rm%d5&k)lj%`@[c+2#K[kM4P1f0!2k"eXm!MD$4Y[SKH"$3i!XG'6J"ZaSAhCS9l
1ZCTAK@l&4XkS&fcS4[D[aiEqB3plE03%QKdER%AHX&%rC[UAf(J$R)B0,F+HpYM
qK`[lfXXj6c20i(pXD&CU(aXkPTP-f1!jpVI(K[DJ&i%0(Q5IHfa`!E2+X&%ck"4
Xa+,RJqeC,QMr%mGQpSqmmbpiX%IF[q"*E[#0dkQp!E`4[!Ndc50E`$a-bpG*$@X
qp6GNBPMcrmpkYS5G1cB1cHe5EfNpGT!!j9cX4I-`l6"Y9P[HQGLKbU#Qh-IDfI5
Ul'fNi*je@GBDk1rIbBBa9@Nl+RPaXjrPqYDd[5cYheQIl&pH@YjIMlfdhfd&pZp
CkmKK[i)PpUraDqbXJPRjGPImYq[dp#2@IileElEfZGBqcfji-0rDDqepN5AE*RY
IE$G+U,-6'1YYR!ElRXEmEXhB8X*UpiH-EHMBG(YGYV2M698Xh,K'Zf,+pU5T80%
Z"C[j5Dp&eQBaQl0d$'eH'l9$1b[$#RZXFEd&N9B9i(4`0KJ"ji"c`3AJ3V!DV!&
V3EC1UJ2V`8D`#9`#0S-YB#Zi&0`#ZR2EGS'l`AhJGR!2Z"Hm9a,02F&phpXpEpm
cGMCAb*Qhrr(cM[Uh66*SelI)IFqmr6rA[)k%[jf)(q`[riNmG1RUT`[1ffV,VR$
ZRlG[[jQp-hA4XTarr#kGK@QIAEESUT'FI`S@A@&p(T!!cmac0N`jmpFXcMhZlAM
i0rBA&QcGZpBCfY[[b2ILHcZq!Aa,jhaM,`RL@cERZkIM'm+hI-jh9FFh$pmaFlj
e(Gm`[Z2RI#qGbCciMT[c,9ZfD-0BIhrKME*HpVim5X''f$P2pZQmf(K-Z,+rF0(
QqjlEZQ([k)L*21d4)QpfcYJ3&bk@IFEjHD3+C`'rTCANrCd3Bqh'pTDE*8Z$JYk
GMM[dlp)baGYL0Y2[QXcL9R&G(,*RFQ66VBNr%%6HJ*0IE'Um)0FJRhpJP$QVqaZ
0JG%ic[I4lR5MHR(BM4TYYq(h8P-6RPl)4e(k"`DdIVMX)lieL"1YK"hTl0cHpID
CrFaMP[BGEZ,ACq`f-PiSb2X,NBBIq8R3)ddXRZ!&fC%4ASJJ%LjIAhPC*l##ZQe
-)[6c3T(4N8[CF9i8j0SXLDrhNmQdU%j$em#k3(d'``8ljSb9prFQ)`D2&iTIl5r
),!FlQA,`H+(%kNJCdM&cG0*fU#YAP9D8,KYBd`l#HQqePS2(#k8[mF)Pe54H@Fc
CSE,@EVAL*,YdB%XlbS+QE`@Pa8`[P&PHf03E6M"i[&"ZHF'Q9[b$aq1&-ARIUD8
f21#B4Q4laVp1YbBcE8MaVD`Q2RrTEJP#[elFi,[k5FjkaJXK``YQ%5[Y)GMFY)2
(#d&i)E`jMNiY`a#X9+Sp!%E0bfYpSi2MSb@lq8VrNFl@mPV05`+cL2,4BpkajG5
SRTDaBY92ASc"NLLXccqdP&KaN92PfU9@qNl6kLh&SDBi0I8--QrHF9YJ0hTjq4h
,DP[XjMB[(pCIX3a8iVUXqGqa58ca-1pJKN5QSLRBSEHBGh5H,,2RMMf!BEDQbHN
U1e'[R#S[G&1lGme2kX1mBfG`I$E@LAG3Vik8[(V9TK2d1FAXJfi$b,`-mV)!c16
L(5f9BE[r82T)Nd3CQ06f98IEX0f,k1`l1XTflk)cH9fkCZ-V'l$,[dHjI,30jrZ
*@`$bB4P3++[XUN0pTmB0`cL1D'*Yr#ZMM5SGBEcDr[,5T5p@KrZ1'AD[U&IHN8R
)$pma413rHXH`)MMa$YP2ijADGa6PQAU0+XSYhXQA$,m$"HHqieMPrr!G0J"&DGk
4lFBXm`qZ3$CBCefqh5[Uj51MR6,YNC%$hpX$P2,Sl1Zf`A@[k+'ZV0dMi"fF+SV
NjhR9KEKm*EZPe3"rM1Jmm`lT!2pFl%8l%QH,eZKbddPSmC2'm5CNBHq*6S+G3q(
D&EUUpJ#&BPG3"+-RYmHQrD2R*DRYbrbTRPIk(GD!RTGPJ)(PrraAhQ*Tk&8090P
,[DVF1dlfUR,[10QV1[k1%lfUiAIB&hT9IINihD[UHmITAPAZ(ID*AP8QKU5c1VA
ElI@IkmXMVqJBBN5l1RdeB[hSH3d`idXpVd''Y5Rd[%EVeEc$+Y(ckJLL&CF9TeD
Y20&*1'GfPik"Xh4Lji'mbe05-9j8P!1[H%P4jYja8P(QhR&584jra`P&1Ib10Ai
2J"r2AP58IIQ)+XSK(ILMGjbTMqJl0LGfdmQcpI'm8Zl,afQPR(Z(28!TjhK4K%1
Qmq@mJie8diG(V%fYG1L,XAjik"qG``&QA-r[DF2['08aR+V6[cD1jX1m`akJ6$F
'*`AP$r+49EJrU)r0%hB$d*qpJhREaIRZ1FAmEcbjKpfmlI5mUQeH1$0!eESfEcY
dQKFkhCjU3h8pAY#jbLPHZ(e',J`i@XYi)Ab+&iaF'(#dMaf2&iT1mF*f1Qq@0Kf
Chm0ZR`IEhGi'pVQjbZ0leXeKRp#cEUlba&jhFj@&&`4APXe0'T+E)hDp@"ffkch
9fT&aAKKhP"I-q#Lfr@$2MiKM0dAa9J6*a,1%mB,1jlI8c@&2mN+X"De0DII1P"Z
l'@Yi[$$fIp#GqIaX`Qk92k%pYdLHb[&M1lMlS$i)lERjXGkRp5qc8LUi,Z[$B-b
b[NDhHp3`RH[UET`VZGlHMA-9ekAG1#MjYQkFDlKHfih$k*rfET`jA*GhimcPZU)
ECalA@lTajR1pY4Z(F5RAGH08FqhSaU%IGRdh$RqihG#0XjMVUQiFrPLjX4ZRRZY
0h6J0A$Gdic4b[ENEKrlHklTa@VLZl-DK8ETM*Nl`4"bkCRGeip#lhYk03mpdCcF
rflRZkFEKYkDlZh&fFEfRTdUFh9ahGq[a$9ahp3k)BemqdLCkVQmLF@CccI9$*!j
pL9`r41,3PmMe3b31IBPF2d6Lm"pHVKmLFFb!Zj%ip"Ybr4#*3lmKe`q412`2P1Z
(5"ck$EPqL-5Khj!!kiG)(2S0ZAk)a+'2N!$VKdJFqJLjISM%BDj*VKmLFCM%N!$
VKdJFqK+jISM%DH@DkiG)R+9FFrd3LF1rbKHmV&XPcLDZ8lTak(2NqLX5"jfHkjY
)((4kVQmLFICaRGD0Fi"VVKmLF3jbcI9r*-jpA(2peKIHrAbFYh(0pAmNcPZjj[S
K0[mclLY-PI8edqc3p)#l2XGk1hIMer2$XAm*Jhca3dpk*h3APd[`@rqmhfYjAi&
pAr#A-hlYHeQ(4GmAp`XpM1V4phPqrU@IB)6AV'D@rb6YkCjmr8ElErM4GrImLZ9
AfFc53r%+e+r42-AIAF!rjB&h0&[T)EqD"mR*PFfXF5K24G*[BhJhqBkr'rfmVCQ
&qUr!mb[PraVrhZT`bUr5Ari'$P10Ai2H8G9+q1II[dQDpA,MeicZ#`hPIS'qZa9
$kr8c+K)RhY02BTYTip'AZFMi2D2HN!#1hQj@ISU-hj1U#ITDFTEpM-Y"irIYDl"
4&p6PR9bDM0phP82qTb%XrA(08r!TE#ZXhiFkHI*[e6jZeaQr"Fr-j'RYlGJkE"e
FU'*cm[UpVf,EDrdZj9*Lr2j-1G,raBV2jR*ZlYIkJDZa2@$m(LC28kicIKXrJm1
$aZrQhl1Zd`6MGq#l1,c6q$hq+'f5-FE[@`YaH*HY2q%RreR'Vrh61,cE[TXmk6X
D0+@&(1,(Ie*12E9q5,h*Kk`IIEXbieHN[,l(q)fjKrH&MGm6Yq,!'q@8kahcMGm
MkT@perL9r'$Q(3elX,h2q+eH`$ZH-RiGF*,[6K[[qjfkDI9rLSeDN!!cpSXLAmH
[mDhB2Q$mhNbGjeGYh6"5!GiQ6arYe'[VICU,m,$0df0F9KQr06GJqk#YHrkIQQA
m(R`,0Z%"8mH5*pqjYJl`ql$0dlr1e0-lp,D2f2Fa1N$Vk6XDDN)Hj06pLFYMaZm
HpAEK3$PV(UF1*KQrTp%32R3+Tr%"jG,iY8cr%G[(E9i[l["@kpl[Bj0kj+bPEJ+
fEPBS0jq`HCh%j8,MYepF6!h#Zrb(SrQlpb&XMaLrqNFk20Skm5eXMaUr*[(8"Z0
RZ1C6aQr*'H62i5(r&m5Ye+QFGHH3!)rcFcrI`YrJm'RMpeEU-hLjmDX@"m2r2&P
i)QMbiG[p%4`qDrP-l!jIlTeq8+-32fIVFV*iYj2TBGhkl1frjR*rdcdmI+,mr4e
HUEhpDpJqErhfcrJYK'Ypm+HTXq8GASr-9im6$U3%T2lb6,iMeiV6U9PSr(lm0&k
6H*Sh3V2#ehRA'Vq)F[B&irGqH#,8Pr[0[P-DiiY@Rj&I*aq4aDTKq)SmL9ld[DB
C(pDMjH*69aI'rN,eArj0p18Y9Pr'r(aA+XI2@RhTq4@*pehpjrN95eHjqLmH$jj
bmKfmD"mfq!SrkYr40i&2+MH2'lpRi,PAl6CqRa3II-RiE8BhU,i*2#bpL"C!BSJ
H8Rd6q2*hm)#Mj#a%XkUq#@`AChr&a,[SSjfk$&i`MXF6*YiGp-q9Ki,,PZ(`9CZ
REh6i,l$fpGM3X2K*RT5r!jr5h!LT)q-(VkLHHdDai8CFH+ZMEi*,a*@LpcPYj%a
e8Q"8ZZVV0KjmjZLNi-AL'Yk#(lAL[#2`HHPADNV1'mQCkU6!Ypq-!rb-(S,M(4d
6H1m[X$eThi%Hd,cqm`qaL8idq80rD&iEDYLqDH04RjVAVdR28@YbUTrZk*AJ"G)
0F*UFQp#&UPH#bml#i5RMGqf21RSPN!$V)E3*+Ih2MPi*A#0pJ"k8mbET!hhhack
-!lRbr4pir3!!!3!!!!%8!!!!&!!!!$)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
:$A0ZB@0V,QeMF#jcDA3!8dP84&0*9#%!!!!!,$X!!!&'5346593K!!%!!#`lFNa
KG3)!!!!!&M!#!!d*FfjKBfXZE@0`'"S%h$*F"2!TdJ!!!!!!!!!!"18QJ1mQ!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$rrrrr68e3FN0A588"!,CQ6d5h,bP"!!!
!!!!"R-`!!!!!!!!VY3!!GMS!!!!!!!"8m!EiZQirfr&If#B,2fqc)lcBbQlKLl3
)*jYD#hIK#b@8F,+6Y[EGbNkC,Y3kEp(LG-&66lib2"1I&m&rE01kKGc#PMHbb5D
hb5,E&aRXb#B,6l+F54EbbhQ5@hJa`L2,N@-,18jq)Ep)ERGX4fjr,(,,b#3,f@3
j4Si[NYZG&a-V[%IYXPrB,FFf@lJ,Zkl@KF`fZ8@bN!$MC#'hN!"0"ZYbU`fD0mV
V(I5aKV6Yd*@I[CHAGQNRGa$G6KDfGG"j[B1&I4eVN!$fAIcX&R[p4A2KJq9ik5h
m-aFqbd&H$RTR#cpha[-@rPQHAlb"f56*3QiCF'!XJ)$aRAhfh,@hp**jh'lK#lq
&%di@XKcCAZB&`!P!`(MJN3G`30@L+(!FTppaFVZGh!FqjZ41ri(Mh%9)i&5Z,kG
rFrD*kYkX'mGq&1FVFA6FUk@G@'[+q5Mf-1aXl"cX)GKCf,RBHGM$X3GMr`"l"2C
Mf)pM9f$RBaGJMm3HK@AQ&Q)AB4GMPf$r%(XSGLPf'CB"1`Bl9Z-RGKaf2(C2l"M
X[YJ*f$VXD1cHf)RB'GLCf!1`Nl$lB5GMkl&6X&1a$GMpXG1`dl&lB4Za(m%HL$d
)'m%@BBZa*9M!))`YaCCKbqeF#(BB`+M%9Q'VX6AB2YLqf(lBrYJ"f)(B$E#$X)1
a3Hb'f)f`'f1(B$q%(B(G(,X&GMKf-qb@f+f`@f1(B6I&ES2G&VXGYKBl%[YKl2E
B(E!lBRI#lScG"EXVGMIX*YK4f#KfGq`Hf,r%rKAf9Za&f-pMcm-qKEd3qpIB,f!
[a[i&pREX6GJ,X$GM,m(HJEd4HbIfZpLr`9k+[3al#rCbl$pK[iIp)[B+l&hB,f'
[a0k'r9[X9GLVXGGJ[i1p&[Y9l2RBkl$ABlq2r3VfDpJEX&r'$X8+IJFqJhd)qc"
f0ICZl$2Bql$Ia2ippP[BEf$[ack![4Il,2B(f(r'2SIp)IC(f"pMr`(l%qccf%H
`hmBqLRd-qirBal&2B*r'2SRp1[BHl%qa,f"rK[djpKIBAf*r*BiKpQ6X+GK2BSr
$RSMp"2C6f$r#RSSp&RX#GLAf01`Ul1RB-l"rM2ddpNq`IiVp-qaRX'GLcm+HMIe
cl2(Bcf,2`Ai1HqjriIqr'!JFb[`"5IJ&Pd&*X0QP5Z!Y[4(m+!&c$)pDj@cCXQA
EM[c1AEYflGke-lpYkjBhE41bVPa@H20IK&,La-[LFNVkR*`QJ@-m8"!6`(58+)C
)-bZ9GQ$kP@IRUk&E@ccJZA8[6JCE06'[f$'TQiFVNPALeQ8S6[9"pi4E$0`NmC,
"iki)@I)F9+VNbl2[&)Nb0FAEBJJ0*!@%J-"!P#""N!!35!Q%"')#BB5X3&`J*4!
5b)lT)Md4#l'"S%"1)(L!)#3'3JGTJFa"BUJE)J3aK0a"N!!JCa!UL"epJR4#q##
H(ZQ$+%*J!96),B68)ik3!%()+B33dZZ43NJXK!p#"kQ#k%(D)(k3!%0)'N338JI
k!HJ303JHC"B3KL"#m#"e%"B)(f!2BB6B3DiKRK"'b#HN%I)+!B"-3k)p`J$TK3a
$5L'8%&f2-%-%)F3HFBB`3ciKc4"X5#hN'G)1QBH)3-BKq*!!HJJpj!0b$M'(f!2
`%%d`!F)15BH83#SKr4!A#!c%KJX!#!`3a%8!T0GqF-#Gh5h)3C!!m%F&5Q*AkmG
JA*Cmj&"A!eam6L)`'"S$34m4B`NMZNb+KEXaa4Q8T"!jdNGh[,`DPbKEA+9P,fj
iqDRfrea"lF8C8kP-CR@&abEhcp8@rETZY4UVP@)'iF(XVrFdpFENGM,ScCa5*rI
QDPV2&r2&+%bL`-XA*mU2$#rQabD&A@rd,j!!1c@R'iIh$rA%R$0cTh1EqJ66L5B
$Cfjl$I@e!*aedj9P`)P)$p!58pK6Q`pS6G@N#a@q"5+DM&k3!!'Ya)d9!C!!(rF
Z)(9V"K&,h)jj0f1*@c([4JeL4*834RVKhC4"J#!hN!!ML"@N#4qc#('%B(QhCKD
#)`dCL0d#Za0fCq`Zf&fa85aNB`rXD1bHf,faBl"MXH1`il(lBLGJkl!6XC1`pGL
MXBZa5l$,X-GK6m+HM$d&ZbSM-5kjGlj&lNfV2$i5#iKaM(M8LmY-U`hJKL9)C8b
Y*@$%Q[YKX)JE!h09N!$M&-8'aCcjH6rd8pm0r#H9p28cDcj*hHaRk@ZXDYCmkXA
Ccd)rG02[P1mLFCabZTF&,6&i3&8lcE&2-12r[8M,YME&mVbVK6'(Uk81MaB5(5f
fNc4UjJpj*pmGaIAN@S)aYCUA*2Q+Qakl(Mh$CAb@jkYHQ[TKihU#IAdFp@kVG50
mE0X2k[RaT64fVdI[-R`)rea[[aIH#"lR*aU9K3Z"&pr)-0N2&fr'HXpb@SCLC2'
KKiKBf+*lVFRGH(RGXqK'9md&aAlAiLC1jkGDUGq%EE4@aHL$4%X!Sda`4m0-p!(
PDi(eEQfUQMFJeq#'AR!Y4B1Ee0cJ9VFe3EEG$4AGcE50+F'j-59$qjJ5fc!qmFh
!pR'3!1!a5I0Q`kGj6plUGU-I6UZGlI%VKKpjZGN%YlH5@+pMqMmm3mI*IR+PKp+
r($#6)![-4(F"-`NkJCR`,$!6h3(-AR"fiVd-,if*&lYQX-e3G!*c2$k$9#Dq&CL
*b`)cd4h!(![ZD0JDB#B`$mbNk!*Q2d'fh4h!l!ARaV3GQ,hBCQ#1"ED23aDBLFi
#-p&VJCRi$Q$fJYYEQ3"Q0lJ(L,ZKZ!H-#h$F$FKj51i&j4`Xji&j(65[!qFX2(F
$p-Y`fJ1S2C!!QJI9APM0!@XRY1E"Y4YHZ`%f6h5kU8iRf9N(hRRicJ(iId-i,d9
kB0bNb81jbE%1cNfDENJh5I+`ER,NS$f@)SmkX6`GBa6,d$e+h9$[CqP%8MG,1q5
Ek$cXQabpd'm5VB2r4*VZaZ9S3#a&le"fdB&BKJ`PL)IRCMC2$8b12$d`13T!EV,
N`$b@)YId(P$2%CCiLYibK,LNRTQe-iG-PL4ab+4)miC-PK4Yb14)XSDf&!Z5+,6
chPESdGl5l33*hT(0N!"%Z'`DRI9X!Qp'fiB`a6R@*SNKGeX5Ph&NJT1%)j-LJ6Q
G'A,Yc#&1#kA*j%NcQUiXqE&)m*PXKTjKppP-0J&NTM1kDhD59#D6)XPN-LQDL%`
Q5B,(C$0dG6YjlHr'$&r2e-`[-PQ5r#+6)Xd[-PP5r#+6)mN[-LN5j##E)BNAf63
k3GN%q3P+NB1e5@)Sf*E%*3HCi#3jb+4)N!#$cJbjGRVN)"2G3JibHG,NS#Y,IL`
5j##ES@IBIA+3!%d!1HL-lTUG*$R)T%L5Jdb+*R+3!%Q5)!IC$&hGANF1$"C-GX0
'ffeihm`acPYS0aTHR$F%S"hhCe4ZM`@9MSYUVr5$MSeIURRJS%4d&34Z6`LL"H#
P'cD*HLA9p+JGelcm61aj0p%U0Jr6fL(&Y)q0'5fCmB9Z@0HBGZ9a86G2V4Um1,J
p%Na2FjqAkBPfEA)X@,MFA$mZ64(pd#3[p125C0!266&!2c"*qrbijS&k+9E"a`p
08-5QX#49D)TG1b!q@@b+mQ!V-68T@YJF'5-pL8LA!2S4,Ac,$di3SkD`pKD[`EU
Qq*B@Hl`S(G,5p53$mZ0kD-mdVaQPAMiEkEB8BpTTp$EH['GjKJZAd`k1YPSCRR4
8kp,Ni41"qc+J5[H%piL#AKj8fiFYfG%%D[TY6#"MM#2j35dm)4dFifIT`03BT+2
eRL!GeMV6D@lQKbDR+!%$UG(a)j[)V4qCB,40BHd$YSB20X@[46ZI)MG&@9Y%%bd
*amNC63Kd96ae![443SdNNTJ63PcKIVmQ96K%UicJPr`M$)9@#`Ga,$4E1!JpHBU
(#'D9ET-QRLX%*BSIXk9ZJHK6HAdmU`p9ZBUkQ@e8!Y&kiD$iKqB,"r@mkSYrQJP
,SD"AXh"F,NU8[Jf@+*qc)KD'$l@2INL9L#L6)m'`rP'@d*'`&CSaj%$)#fdBI!K
jL9k-bBH3!0FJjlhUMD1Z$'jP[A%N4S9q$$i8mG#``BHLiFD"@k1[MT3'4G0Q0'*
@MK31Kfja0Y-N4dTq`ib#P51P[q%8+TSdMK3"4B-'K5!cHQM4-)ESfb$`K8rL!`m
m,ah#3*q%d%DNQUT!Rm5j0Zrri2[3-!TUjVCS*LQLBd%*CiQ3!&J)"EqJ92ffFRB
h%H`+5T84F60bShbi6I48K&*48%U(fcV22)@)@9$ULL+U&N6m+bL93F5k4'FRT0P
#F!eB3$G(iSd2J68MXb)qG#LB0Acd!l%fI1!'IF1(@L-BJJm94!6Cm)%3#,RKqc8
r#))Cf*%I40V`-428LiqC3-30(ce#j!dI)Qk)[H&$p!`r2J6+9+8T,'%bK-r`b9`
B!64m#+)KISB2e81`!KqUPQ!G2P3P%82$a``KLSB2&8Q%dI#K'SN`'Mk8(*P6I+K
")S#'lcrj3BJ11%AM5-@V)X)YqSB236Y%k[!aHiM6i@0qA-f2`%Ee(Hc&4br!0(b
)db&5K`m"1[ci%+9$T!iI+P@)eH%$fa#Y`iIU)m*eq&$R4,`1(iUEL0MK3lN6i6G
mU'-bArM!%X6Hm+&`#3lJ3cd6M-@(FL@#HIJ36D-r8!P`(ck!$edSK1c`SFX%f1-
$#e3GTdJcb5cMBai3N!$$4jdUE93Ni6j%pr#"LiMIi8-`MeKm+&ND4"8Ir!2mamH
X-bri8!p&h!iI5Tp`'AbJ-N*fq&!D9Bf@)LQ!JLhi81p8jPVd6rbJc30GBZlT#6l
i&L*hq"!M4+J2(rL)F#%qjKY"3(c-VDU-&D[[L2[Kmp3rmD(JL4mIDUa`,R`ST"T
&-['KeST`(cl864%'a)Hk+AL)$dl![1#MPf#&R"*a!J6qm)&E##(L!lG3mE6KR)L
6ZqpI(`V&8k!Ta#f)KD%hcUUZR6$68GLTf11a*f$2aRi@H`lfA1`&f)ZaPf![a9k
'4DdhV8'eE&fPU1UDr0cDMZKI,*YF2L3PNSlc,5c($a**NdD2LZ*jea0@Ye0I,Bf
rU43LXlD)ea$MPeT"&(2Aq-DCk*QdYGl5ImZd@F+1bcqiQH,'J[q+-i8(4jHA2kb
ERq4j9Hc0HRD!JHhAGFPG"FhD-rR@(bm[Im2Hq&RDcV`9%9iI&`ir8aMJ4[P3+GV
DfikRJ)bk-DV(B!%UaVa`5Hcm`+-5P*!!H5N$(q9@QCF5[()"5lLP43QC'h@8P&&
DePF[KTI!AhR&JrSbYp#m!NSS*0XmMR5kl2$8iG(bq1$iR(fdN6lQ(3JM`Brhrhq
9,ST#YhRV9XJ@8'RhkEN56I8YGD``Lc1)&[2E-Y#DrfdCD-hrMJadE)cY"0KLl6L
kPS3G3,(F)M"9U@EdYLC-NP#@+*ZYm[m5#'mFJV``G9AL,6"A![d(LP0Mi`2jJE(
4Q9&q'dV&QC9G8b`Tae+al82%(BaZlfR`dReEbhBHdK0AdX8A@V'ZRM8k1RD9!4#
1Ul)5pVM$HjVpl120hD`Hc@5l#FXSbf1M0RjhZlI-(PB,CeIl2pVQhG2'Ip+bk%r
CrjEGTpcrmIB5GeqlUFN%QkI1eMXaqlI'E$NP!JTPUdT4D`38CY5#bGi2!JS[CNT
%[Qe692#8&')+#Q+[`&k&[4Tl$ICDl%hBQl'hB'r&hSDp(AX(pNlXAGLlXIGJlmA
HKldIqb$fS@b9TCMVi69,ZCGU[br6[MN2l*-D$NSlhM0QfKP+MVe"DLXSZ)JUe%q
Ta5L,40ii@TG+#lZH&993&C0r&*b+h8SN"4D8F%V+THa4blpL5p0TC!e&!%0mC@8
[4"A&NE*0H3S&&4mU04@ij)l(+$*94SQ()SqMIF@Ur##3!)qpd+UVab+88abTd03
Fm1[8jfKhY$lPk!5qS(VAGlqANLmS4D9qZ+3h3DR(p(r5+k,U%T3#cB$!9fq#8Md
CD21Kr,0"@TbKId%ThJa+Jk2N#NUjD,!I&ZQ088RDX*J'[,X,kHhF4N(EimeH5+T
)'`HEUY38NSV2N!!CMmdq![e5S"Nk&VZSYS5NQ$*X*RC4ZJPT*lEKGa%S2ZC'9D&
#fJm095KK&D&ri(qc6bk0Sh!6eVXrYKCL$&'*dHf&`P,p3E%,(dScHP8CPKS-kfA
K3`''0E[`SGLMUP"KlCU'qJcM$)YKK5jme-QUAIL3!0*!F3QIp-&6KBT)X8C9S5,
DXde9S5*5Q&&9U)J8FP39+[+2r+JU9*(H-DSU9*'8Re39UNM+4US+953P(P@&+Y+
qDUS+9549)UA[4GV&69@KM!+2UN)9LlQT+P5ahM5U+P5a&*i8SSZP0U5U8-95Y9&
9U',Y(kHU8-95m9*9U')T9UNUP&(#d3H'*CSa9B8UN5+8UN+9#!09&DT%'+DU8#A
DHdj9S8Ud6jbU3T9SEcLP-D9LN[T'[&3cTUT3T9+%8P@S8UN0U5T8U@CG9D&+Y4Z
GUN+9DNmj9B8Ue8jbUJT9TMHMUJT9*La39DJbp899SFU%fkS+95EF8P@S-ZeSTkT
3CGTC6P@KbV6(R+T#P@Xq9"@UA0LKUP$PUPP9SFUPE+5U81AD*8p9SFUe#jk5Yh)
TD+NU9)9kTUT3&DT*Vk`Ue&09KDT36DS+95'9*e@&UK!QU5T8KADf8e@S5Vf299@
S5Z'8UN*9DKj8&DT5LNUU#P8T4699KDU8fTZqYDc8ERQU#P8P(08lj5V0PUT#9@P
@pIkk5M'U#P8P06a9KDS5je"9U#VYKUHU8&95c9*9U'Upe999U'VKNGjZ9kqT3P9
,"8j9SDUe%jqU3P9,98p9SDUPZUDU8$9k,kbU8$A#@9@&UY&mULT8MH*9&DT'Hrf
T+P50e,&8&DT'5RfU#Y9('+#U8(h%*9L[$"ria4jkq*J6X"%IUR(J2$lQJ"lLBjp
!pY56deIAqZbVK`r13djmB#8BL)pC4G%-(r@Jl)B2$S5+(clN!jNlI+L6+3IZTrI
@l,U($ekK1qre%kl"er!a5q`jL!mP3,J22VJ#kQRiQ!0iXCcqiSMJ'cli$a`6(aJ
$RZ"M9P(X`NFZ9-R`XDdBXiB2h+*H13-d@r!)I2!p-"NIq!er`3H@`CIa-61S-q&
MEd)i&$ji,6X9i[XhIZ!1FJEU$S!mq1!rc!iqF*0G#r%aYbLQiD-fF!BIR!094(c
`5rB[P,1"jS!p$2("ppM"%"mFJed-mB&al)1)MlN#"r#"YHb-L)mjJ#r,'D5E-P6
jm-&M`APmc"Dl)H)$Ye"c`dGrU38IfLfk$GSJB5'm3mjJi5ZUKIMJEbMpiB-r`(I
`J50`0hc8a&d%2M!!Liml#E!4(p`AY68j'qUY2V`9(ceMA[$"'pP&%4rmKjd8m6%
6F(CmB*CUcQbSq6%DNH+M"M!0(eb%I4Aar6Xr+,[*f8JD!1!r2MJVXim2(SYb(cj
`MKd9mF%pZ)[!"`kbXb)qX!"&5hc-$$`&(lQimm((lST`IcNEkeB6$-G([jN,I'!
f5R2ii$rXq)J2R+@(q*KEH#8qjKj93AbSkZ'A-d4hYklHD1!YZZ2J(J!IR*bG(2(
"1H'5q-"DZ$BqjKKHM)mj4Td6(c--KZ1MAq!B2ZjM8-56-e4c6*ra`I2Be4%IGE1
c)cji+IG&q1")F!emm!6fBE4%R25Z5S%*2dkN(Aj%dq-f,QSHANhf&r+PCLZ+8h,
Xjj3VXjIFBpdJL0JiSmi,@Njj0QmNYNfL4Q5"cCB"H%@'1S#3!(8LGI4UrDCF+H6
SD$D+JrTJM5HZNr2&3C)0Rh"hlrARKqX2$Y)20fkEKriP8J64j6m@12*55Y8aPf$
0*Hr"DJ-E2,ddG@41&CRB9(2NVYNd*af8'!lFX3&3T`i!APHI1c"AR*VS6)'*L`q
&5DUGTH*BTf0HmpVhF!4Sr9BR1T[)k[E6Lp"q*T[A'K)[Pk[eTXUmN!$T+P[MdV-
PHD4lC'UYf0cAYi94JiKQ*mT+9q![!$J""3iNUiRpQ"Fc&3'cemK5Va9(NXCI($Y
f&j*%525'#'-QULQCAhlQ*99d(EZLY(#T'rYH-Q+Ek[flU`Zec&C2a[5%M2A$,-k
IfI3MaqB0H"+E!k6A"8MY#*!!A!`JVIMI*,2IT+dIPe42V8q4hNkLG3q*j()0kGd
Lr,dD[(dKr-d9iJVicE,hc@VNbD8,@RC(L1pd!)k,0r$%%bjMIF52l0R$lj',Sqf
k(kei*Nl00peDjYh($8p8k8IFZF4VG*b0lJN[FpEl5ekFH4VmY(DXf"4Q(,P)9aD
YHFEAI91)m6+GFDrdRBUA(A0ELR*IamaaXYArkLX2Zmh@5Y6dY,e33ZV%j*BL"#j
Geq+ikDENmJYHe%$U2PE18J2ibq[&5l!6IiJ6'&Rc'GIfJmeD#cQ"*AU2Xp[J`bC
daQ,(*B8H'kE([-42a2"DGaA8LDU9KjQ4Tb3,Nm`EEaKHGeEQfhESrcL[&LJC2C0
He8BV(P!JeN8h+ZkPbm*XNef@rM%iKL$1b'E)jBU0mf3cH$YGrCaMd,mf)B(TU)&
MGk'%''@URl@95@&ZU&I(2Qkm%)@QP1@e!2Kf@F#aP1,kiAPdGhNFeYc%Uf9clBE
162fJ-k[-A'UjJY3Z!'RUTLhb@kd4G0Q8G&K@N`FC%d[6e'SA2jAS-9GNErl#2)M
Ude[ZI642MZAjkS[fSCac3U4dHF6H*mX@dkL9RiLdfdEdd2YMEm32Db01pQ06``A
j$I%j)c1md$fMd4LCB8(bq,SNZKQ*6Be0q(bK@&Zi4NFZEF)Z9f[4cYZ&C@pG[HH
1HkBIFf1[[ZUhNH&#5ADr%'eiS4Il2G,)iRTFN!"0Rm'&+#4KZrhP9hN#9rQf-BV
3MJYPKNG1jDf)--KjD4bpfiXANlaZ'TDacC4CbmJmP8JkKlr3Q``BI&`SIqeq3Gl
Vf-QBJim,&CC(bQ1QN61,pSCkZ0kGl@"@(,1VA6RiZ-"Hj1fiX#@2+(I*QhHZdpX
Y2F2HU[2SeRV'&pK*"eaBe"Z1-2Li8'ea`DBfr*h(ai@Dl0j*AP&((A-416hPVG0
KmHSeT-3L0c((k!l-445&4qhfXh[UX-%&Ge0)p`l"jXBGI&`)GIEEXlSG1m#5&RB
Br@FEh+)DjYKKeYDa[ahGLk2RQ2d%6#ThX`#Vh'%6`i@ZEr@YV5e(ATi2qMH0ar@
(e3r'9#UNFdl0@9AKGdpmP33j,9ZX-,P'ZpZJZM9JDbpVaQi0fH-[heGkF*p8!88
R-cpIE&SQ#XAFeD*QdeJk2"Df!kX$Ei8ppVLE0T[#aR1R3H0@B%r%VX5Z%NAc6ZM
F&drhRrYlZhG'f1Prk8ZEVmFh,'SMYQ(Z1rTIqLZVd4k2Ya2"`r`dEBd8#XIC4+m
fDBH$[(dFLGcfh(BY63V(kiZ&2B0l#[@SPK6FPQmh#,',R)XH(2flR,1V1[5Smd,
rZCI-$G#`(8-CrMJZ0`XM2M'dimK8KMmP1ake-HFTCZ3E$b`jQrB0C"'V1K(1`8,
ZVU0Rajc5fB+Mf-erZa-E*,Cb26CH5BMBU[AB%cZaB@+Vef0RGf)Ma0DXaqlEL5d
LYYpkl0DVRC2B[ZZa98-l$X`@#VPljGhfTl)X*3FLCl2m@e#aLHMrSiAFpX1I[RM
d`0QC+C0ja1I)[0MCF#$+h5rr0PZb6!1jf5Nk(,&kqGS6+TFV23"fZB,#c"LIQhP
9i9Ld)@C8UlAB0kYLVcQQML9hVT)m8I(f`b@IZf4kjkTDjAP1V@XA#QNlNdDRlB)
"Q6,S[+RM#0pZ8r*1(G1UdhCVPRF1UiGB"LCaIYVmlV8H,028!FI*663$fe@,U@2
Kl6&lqGJ$%'CT%[F!826@99i#Jc9Y)[RHI*JkFTY-&ZTJAYh(f#`"d3DI3mbG[3f
Jmh,4E!'i-kD1q[+Nh6dRHjSfXFK-4m1Nh8RRr6SDLhERRIIk1RAI`@qp8QKD+@2
0DCM-0SLh!26$-X"3CYXeFpT1FMH1YY2,G**VGA69XBhGkHMhGH3DmPSGA8$qHKh
GM'"p(@`cm2ja'H9lmaTMP#blm0XkB("H(@XRrl8kE!#-dY54[ieK&j5AjfbCChF
kHZI)e@2ZHU6RJ2If!+EFqiLUD8q@0BGY)q`!GA"U'C*hqkV,5!ABSb+((cdmcp3
K'LV[NVhBMF6l3fYiZEP*U2GBH556T,6ha%f#RB2KfK9Z9Hd"$-@Z`!Kk6f'l5I[
(RCHdYUhcrh2RPDh$'R$RC4P!B&'irAdYPSDlUSiTHr1ZUP$(+hG9K6THZDYD9mI
kZkVZ1Z`,Ge9YrAMVVUUYMVIZUJTef#IZUR)jG2fRVX0Z80fe0Zm2eAUX(hGH(FM
ijTeA*m,D&1kmHZI9e''9Z20Up-1(IbLr02c)cCZ%$Ij6P'(U`['9[NXTQ4a[--U
1+YjNP)8kAQ'8K6THBC6VkPM2+,[VQ1[e!(KipJDME1Y(M&&fmF$AkhK[2Q*eb(C
FPS$jH*8TYrAM,DCFU--H`*3,Z#M%)AIcjGE"0U$C3a(c%NXGfR)XQ#apqqD`!aN
Am$bYZijH(X1TIH9TBfmr6"hf!'E+'PGfJ(lN'HjrcFIL"EYpj@rVF$HcY6ZH!9B
Ba`kV4"R+kF5J%+eMfaXJf'$dJ+b3!$F8PUN6IZjpGYGL%DDlrN1R,fQ9KTplMpf
$eQTbl,$hC(Di!`mUQjkDXTZBZfISrZNM+qpebZlQfG1F0Q[$Q(eA*5)i8CSF*qp
LqlpN,9[NEL5jiaXUHGPB-err6eM,jYb01N3b@iR0FUQYl56V[mck6lEqbkhr&1Z
r`2U2AUZZq2ZZ,6e$MBl01FVqhfVrclArCp[rKqcr,EDfdkhrC[YrNrfrarlIDrr
[Xrrhfrqll2q$p[pZqhqlrEr@rPpMrkqfreICrp[Xrjhfr`ll2pAqAf(r9erme3Z
AG[ah$Raek**rM@8,U9*f)j5PX%8TF8J2ZedlfhI9fR'%P@rMba0DehEY,(m&&f6
jC"[EVThbQpej6R$KU&@kN!$FE5`4D#h$KHc1F`BA$&eShRR0#l52(4mAG1FjLpd
1TVBh30$Mim+!@ca59b6X#,5BiB,mpVZ&#krZ9'N4@lE5ai8"2IKh*26iJYKC4I-
R5k3[$YRRGdl3V[G8@b%pJ3YpVq1#B3pXG-`Zae((EJ2YVi'FbfF*``AG`66*)q-
h4hUAj2fMYfXhS`mq,[5jmpjT"9UBdENpHf!0VB&@-ecBU$IGZeR"KBhC,RlGaK6
@da2IqG$D-J"@13d@FcjilQbE9U3IXm"-j,XcBLFlX[C@S1RkBBqA)5Jfi1LJVL6
[35D'IZUlJIqN0a'lMDBA[[bk*RjQc5ITIlc5ATYI"!,FqQGiFG-2hI6Ej6I[*a4
Z[rKCkeUpFHI[QGf0R)FrB')IFcDHr-*c26cQ&G!Db2qd2Y0ed6p*YMrQ&-F@r-l
TjYQ*hk1kHAEQGfSh$ebXSCYR9hlhlqC"i'9k0mrZr-lSjYQ$hjRG2+2jr@Jhcjl
m(YE0Jq$&!GdmBrKYl1EK4Z-Mh6bm86U`QiI0hfChmr$Qi+"ZRJRm(Yc08mI[NGd
m%rNpT*Z('jT$ZhRUqCh9cF09el'VHC,VS5AbF1ram@iHEKpAG20`kh9FYcmm1$Q
TQ`FQ0+4EpmRm$ZhQ1BAI%GdmUrKGeHh2kIbHf"-NckRmRYUGLp2i2Hh9HLc#aaD
heCp&MPGCB,Ek#em0X-0!ikaj[r-%i[rcbeZ)MPGS[IRP,B6l"1)h*6M1'qaX*`F
kNNR&@Pk'1mK60iGlJ2LkUaDAdhqJ1$8f2T!!(aJER4RPYk&8R0&c%B[+m@q$`XP
AhV'KrI'KPF$BQb%rhUib'RDBGh%a2,MLG4Fb2*!!Gk4+'b+V@'(91JQmArVmU3h
*deB$S"A[*GkZ-KU@',chm1$+HjlpClb2BB8&j!6[+8mIP"VEJTUEqY(eNIrJQ,$
Vk`GaLT1kZIr-KZ3,+ckMJK9Z2pTjY4412R@kYdCI8Bp&LckFi&hfiM-QX'McYCG
kMclEff6%0eelKhMMMU([d6ml1dEf[[FC*lHh+Ym0(rlD,hrUEHGY*V4+1D@r+AM
`RlKc3NkrH5KFAkRQTE4*rRM@ZZrGq-0[9`*UUIMIVJh2kKK3M%qfdUMX*BREm+S
R`p4GbK3`RFpRmC((#qp4Lb+2$`e[R2rJc-E(6jrIN!$mfIV,'r(I*"b,l(hXJQa
i,*Ie2ii91h9f-drJRAAN[2e'*imIC[j6q1'YiY+he-X"2`CPG939CrBG5If!erR
cN!"1IH%1EMcpkjGaiqN,klLa`[6GaifC29&`iqf6aifCeh$$'k%Ylqp4J"Zf1#d
IZm-CF&QZcI*k2MJQ["Q1+kTCB"L4'B!20KpU%j@pi##JFA6kREhJ8-!LG1b`Ek(
!`28i'-VTa*,99d[DAXRbGZDRD@ZN80$@hE9*1abX4Fe#+ilUl9UD&)lA&`Yl"[F
8f*9Z@F&YqB9HXe1I8hMDm4IPZq%M[r1dV*[&8`BVqB&r9hMDClBdrKf&*kPP&,q
&MG3Nce4q#jYq5ClMq5eXjL9j6Z#hX*QAj$QEhm*QEC,RA(i,'ha*RJ[i,@`B*RN
ZjEH``CIN3IfXX-'Aj,QFhm)'Aj,R#Ri,Qj**RU[i,@b'*RP3D5aXQLCjVZ'hX,Q
Dj,Q@hm)QE*,R*Ri,QmP*RT[j,@`k*hPZiEH`HCRNZCAI`XCfNZFfIJXEXdQHfrN
YE!JRHHlJYl!aQq5jNpr#"Qk5jbjq#a[45Cklq5eX1LGjlZ'hX!'Hj,QAhm)'H*,
R2Ri,'q"*R[[j,@b!*hNHj,H`fChNHBMI`SCVNSHp"!XET%QHKhX,j,'!Ri3#mM&
iMrPcUiVEUS"mc2NH+V[,j1qXcV4h9TI*ZPQm1k[)$rBHZ,0klEKUYK@(h40q)e0
&USf@UA5YQZdaAeVI-PcmRpB1QjkDEG%Tjp4P0GXG2l6LXRcXZTNp[q1fHG`ibq,
'aE)Th!Mp4Zm(h+LdZ"')3YDarGEAlq$'FlV2p((MZ4FZidCD2AY(h@[D6A$MGmF
ZF8FZLYaI9Ad,Nr6+YY@(I%lT*+jT3@0RY`6U*+j*KLe#A'!hF3XZameIU82U#he
j0@i(kLiqCHT,a"@c6@G3F9+I(qHmPE[!dZ&QQLf9l10fTEC%r3PaE,RTaj9V(H(
Kc65jNLqL11e6SZkp[NEGfcCEbC@iX3r3ljfDDH0+RdSrSa'6ZZQhAer9,Rj1DUD
"Y[MdiajRrQ4aY-N*5lhGTpc$6&bG0LLSEFAX51dF%YrDcX40CXrBF#Q,#rET2Vc
@cLYha@'6liQ[i01h+*2eEZe$*ZiCEAl+YU[%dCmb%rH)HXpfUh+Qr58rCjQilcb
'Mfe@j8`r`FmN%rHmHXMfUU6pa'UI3Rq,6jA1GqG1Ar[N(09Za!IBHIV9DTrQI44
ISjeAjU2%p28&h6q[Y(&E#jrFZ$[8)lerL+#a(YLHa8hjDEd62mr%,3GAK[bNL6[
ki`5FErXRGp9&pjUi-l@k!QmLj&a1AiGZ0R&2hNI!KEBqQ6RRp5CZqUm3S*KEp%[
mD"eefQUG(K*hC@HHT[bX0UMeYNLi8F2[aT@TVjqh1#4h,-lV60`$lbH!'XRh$Al
f0(%hD"2@,eMmir'%eP%RlU6FX3kmG,jSiKTeMhf*LDZif*QE+GjIi'-@U+1230D
0QlJ6(fmq'(RCdVENP*dE+),HDG4mSM1[8ckY2E*jdd'Vc4X,0flZ5AaIY(22YV+
lQEMc[amIEcZBBcK'TCd$iVjNkk!QRDI2U6EQL$kaYlA1de0D!Tdqb+PqJCq[QlL
6pBi($+42mNE$HE1*Hd,[%R46KkMkF9N@9lrmGAbmq@$qqRC`DmVC2m%Rq6N0R`H
2G@jQrJd"epPj![mf0A&R#)Z9[jD*!f[r9ZPp`!d@lhrG`G%T#lT(rl+*Qb$F1G,
%'D`"(i"@HF[M'"abcJKEH8X#V%QGSA`@&lM[U`6`GN612@b"'[N&%cG''!cqbrQ
lHmRRpL0`qZF*q)VYRp6RiZA+jGrAmRqm'@%N"`Yh&lV"&6jh)$JDq&M6[EUXGhR
'&depqha8lcTi8d))mk0aHm1C!Z#5LH2IaIASTX2i`%!jUq'&%G2[k,Z%kFbXR%H
'LG0mNi66e!M-bYa%hQALSZSCEd@!1q&0iEiXEY5[L@0mcGE0'a'h(p%"c6#i!Ak
FSq&F'&hPSpA#8imAaUQdmc2JB+RiA#SZ-$((ch1@ArTaT5qZm6mrlK$k'Z0rLAc
2GqBMY2dF2[#I1'EGj6I"MkJhp&-1'a"XFYV%ADmF[('4maqmr9"q%rbXq#*F32S
AJXmT[`Rq,YKQhV$)13MqT2`Qq)3`NMFV%M)5hU"c'GUU(MpJiMD"YbN1KBDdIJ&
[9m#rkJlq"FH%UA"BiMEVi(I`DHhCc4X@3X"1jA22r"%qX*%iX0cP0k(G`NVGXIP
#F%Kj8R"'[1UE&PrK5bj2#Yd[M+%@kQ!VB,H1i'q*[c*68X,1ph4i8[!2hd)%q#D
RMrVZmTMJMrqe!%MVJ(pVAjr@6(rEaX&[YDpe9Ab2fMKQ92Zk@Rb1@C154i$(bPG
#@p9lGfd5ja(Z$*5[K)CH6m6MTSk$aAYG[K,-q"$F"(krEBH[""m62hM5e!'X+&m
*2[Yc11Q9a)hq"[0UjQEPm[0D'2)TLpq61h`Z-,iGhhG0[M&J8[9j%hI4Ma(KEUM
T9*6h-4-h3TcfHbCZIfC8m5D`p5H)q,lPIea+p69eAkIYb1'HNLm+rh2l)A9X6J6
h$-c0V*9qV&cqXPC%I0ENDf3Z2Al6S(Z&(jLi3m%Nj3H")A&8CPELCX-4P6m&I'e
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!#!!!05h!!d!3J"K!'-!D`"R!'3!43"b!()!,J"S!(3
!E3!#!!)!!!!!!!$8[l@f#&feYJKG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!&4&@&406e06!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
,%`!!!!!!!!!"!!h[XJ!!!!%!!!!!!!!!!!!3!&N"3`&'!c3!!!!!!!!$!!!!!3!
Hl0l*1&Tkhq[VKl9Kl`rY2(&Ri2,J3%fB#0H6I-ZB$qA"JEFr6X526Gcai*h(Udi
AaqD1KIPQcXemV&`qUjN%cbAZ$2LE1amVPcqTq`pk#%5!8bk2$,M#V4FXRM&[QZp
(iTSrXlb@lBCeRPD,`rcFpJq-86lhV,Mb,bb2)Cq,"i'RG&Ia5a1hRfE&jD1"TMJ
Fpc"bkM5M,Km0"1+LF)V!r`-!!,e+!!!"!!!!!43!!!!8!!!!-RMIJ(I&UbJ6i-*
C@r#ZH"9Pm"*MLfeiel`+U`frap(XN9Y4)RkeL("Zq-r,-E(Z51&K,B"hHdp&rm[
8RUkm"4L-hZh&p"D""aYi9Xcd2SZl#harh2&6[9YkZld0m!5p%ErK!eVd+kMIIk-
$RK'bqp)G8p)30TjZfC+'GmBVVj0++aCq&m3lLkUCleG3([cq`#hNh31k$,J[DXQ
VVYa&fPHXh%AX"rBIFr00pk`Uf,0a+NFfrBl[(h@AU$bCl'rAh#8U*JdaXEX%-G#
R#d'I,RMF4mcMkFC@mUNdK(3%$KV'12+4J*XKTLN!MFNRS9f-p`!!!"!!+`!&!4J
"pJ!!!!!!!!-!!!!"!!!!!43!!!!8!!!!-J6Em&JJ8J!!!"`!-J!!8f9dC`!!!!S
!!!%8!!!!&!!!!$)$f5dS)d)!!!!F!$)!!&0PG'F!!!!+!!$rr`!!!!!$f@rd[2B
:
!!2rr!!!!!!6F-G5f!!:

Changes to snack/mac/snack.r.

12
13
14
15
16
17
18
19

20
21
22
23


24
25
26
27
28
29
30
12
13
14
15
16
17
18

19
20
21


22
23
24
25
26
27
28
29
30







-
+


-
-
+
+








/*
 * The following include and defines help construct
 * the version string for Snack.
 */

#define SCRIPT_MAJOR_VERSION  2		/* Major number */
#define SCRIPT_MINOR_VERSION  0		/* Minor number */
#define SCRIPT_MINOR_VERSION  1		/* Minor number */
#define SCRIPT_RELEASE_SERIAL 0 	/* Really minor number! */
#define RELEASE_LEVEL         final	/* alpha, beta, or final */
#define SCRIPT_VERSION        "2.0"
#define SCRIPT_PATCH_LEVEL    "2.0.7"
#define SCRIPT_VERSION        "2.1"
#define SCRIPT_PATCH_LEVEL    "2.1.6"
#define FINAL                 1		/* Change to 1 if final version. */

#if FINAL
#   define MINOR_VERSION (SCRIPT_MINOR_VERSION * 16) + SCRIPT_RELEASE_SERIAL
#else
#   define MINOR_VERSION SCRIPT_MINOR_VERSION * 16
#endif

Changes to snack/mac/snack.res.

17
18
19
20
21
22
23
24

25
26
27
28
29
30
31
17
18
19
20
21
22
23

24
25
26
27
28
29
30
31







-
+







# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

load [file join $dir snack.shlb]

package provide snack 2.0
package provide snack 2.1

# Set playback latency according to the environment variable PLAYLATENCY

if {$::tcl_platform(platform) == "unix"} {
    if {[info exists env(PLAYLATENCY)] && $env(PLAYLATENCY) > 0} {
	snack::audio playLatency $env(PLAYLATENCY)
    }
110
111
112
113
114
115
116
117

118
119
120
121
122
123
124
110
111
112
113
114
115
116

117
118
119
120
121
122
123
124







-
+







			-variable [namespace current]::v(in$jack)] \
			-anchor w
	    }
	}
	if {[snack::mixer outputs] != ""} {
	    pack [label $wi.f.f2.lo -text "Output jacks:"]
	    foreach jack [snack::mixer outputs] {
		snack::mixer lines $jack [namespace current]::v(out$jack)
		snack::mixer output $jack [namespace current]::v(out$jack)
		pack [checkbutton $wi.f.f2.b$jack -text $jack \
			-variable [namespace current]::v(out$jack)] \
			-anchor w
	    }
	}
	pack [button $wi.b1 -text Close -command "destroy $wi"]
    }
249
250
251
252
253
254
255








256





257
258
259
260
261
262
263
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263

264
265
266
267
268
269
270
271
272
273
274
275







+
+
+
+
+
+
+
+
-
+
+
+
+
+







	if {$data(-format) == ""} {
	    set data(-format) RAW
	}
	set data(-format) [string toupper $data(-format)]
	if {$data(-initialdir) == ""} {
	    set data(-initialdir) "."
	}
	if {[string match macintosh $::tcl_platform(platform)]} {
	  set tmp [tk_getSaveFile -title $data(-title) \
	      -initialdir $data(-initialdir) -initialfile $data(-initialfile)]
	  if {[string compare [file ext $tmp] ""] == 0} {
	    append tmp [fmt2ext $data(-format)]
	  }
	  return $tmp
	} else {
	return [tk_getSaveFile -title $data(-title) -filetypes [saveTypes $data(-format)] -defaultextension [fmt2ext $data(-format)] -initialdir $data(-initialdir) -initialfile $data(-initialfile)]
	  return [tk_getSaveFile -title $data(-title) \
	      -filetypes [saveTypes $data(-format)] \
	      -defaultextension [fmt2ext $data(-format)] \
	      -initialdir $data(-initialdir) -initialfile $data(-initialfile)]
	}
    }

    set saveTypes ""

    proc addSaveTypes {typelist fmtlist} {
	variable saveTypes
	variable filebox
1094
1095
1096
1097
1098
1099
1100


1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112



1113
1114
1115
1116



1117
1118
1119
1120
1121
1122
1123



1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142










1143


1144

1145
1146



1147


1148
1149




1150
1151
1152
1153
1154
1155
1156
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125

1126
1127
1128
1129
1130
1131

1132
1133
1134
1135
1136
1137
1138
1139
1140

1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159



1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172

1173


1174
1175
1176
1177
1178
1179


1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190







+
+











-
+
+
+



-
+
+
+






-
+
+
+
















-
-
-
+
+
+
+
+
+
+
+
+
+

+
+
-
+
-
-
+
+
+

+
+
-
-
+
+
+
+







	if {[string match horiz* $lm(orient)]} {
	    set lm(height) $a(-width)
	    set lm(width)  $a(-length)
	} else {
	    set lm(height) $a(-length)
	    set lm(width)  $a(-width)
	}
	set lm(maxtime) [clock seconds]
	set lm(maxlevel) 0.0

	proc drawLevelMeter {w} {
            upvar [namespace current]::${w}::levelmeter lm

	    set c ${w}_levelMeter
	    $c configure -width $lm(width) -height $lm(height)
	    $c delete all

	    $c create rectangle 0 0 $lm(width) $lm(height) \
		    -fill $lm(oncolor) -outline ""
	    $c create rectangle 0 0 0 0 -outline "" -fill $lm(offcolor) \
		    -tag mask
		    -tag mask1
	    $c create rectangle 0 0 0 0 -outline "" -fill $lm(offcolor) \
		    -tag mask2
	    $c create rectangle 0 0 [expr $lm(width)-1] [expr $lm(height)-1] \
		    -outline $lm(bg)
	    if {[string match horiz* $lm(orient)]} {
		$c coords mask [expr {$lm(level)*$lm(width)}] 0 \
		$c coords mask1 [expr {$lm(level)*$lm(width)}] 0 \
			$lm(width) $lm(height)
		$c coords mask2 [expr {$lm(level)*$lm(width)}] 0 \
			$lm(width) $lm(height)
		for {set x 5} {$x < $lm(width)} {incr x 5} {
		    $c create line $x 0 $x [expr $lm(width)-1] -fill black \
			    -width 2
		}
	    } else {
		$c coords mask 0 0 $lm(width) \
		$c coords mask1 0 0 $lm(width) \
			[expr {$lm(height)-$lm(level)*$lm(height)}]
		$c coords mask2 0 0 $lm(width) \
			[expr {$lm(height)-$lm(level)*$lm(height)}]
		for {set y 5} {$y < $lm(height)} {incr y 5} {
		    $c create line 0 [expr $lm(height)-$y] \
			    [expr $lm(width)-1] [expr $lm(height)-$y] \
			    -fill black -width 2
		}
	    }
	}

	proc levelMeterHandler {w cmd args} {
          upvar [namespace current]::${w}::levelmeter lm

          if {[string match conf* $cmd]} {
              switch -- [lindex $args 0] {
    	      -level {
		  set arg [lindex $args 1]
		  set arg [expr {$arg/32768.0}]
		  if {$arg < 0.00001} { set arg 0.00001 }
		  set lm(level) [expr {log($arg)/4.516+1.0}]
   		  if {$arg < 1} { set arg 1 }
		  set lm(level) [expr {log($arg)/10.3972}]
		  if {[clock seconds] - $lm(maxtime) > 2} {
		    set lm(maxtime) [clock seconds]
		    set lm(maxlevel) 0.0
		  }
		  if {$lm(level) > $lm(maxlevel)} {
		    set lm(maxlevel) $lm(level)
		  }

		  if {[string match horiz* $lm(orient)]} {
		    set l1 [expr {5*int($lm(level)*$lm(width)/5)}]
		    set l2 [expr {5*int($lm(maxlevel)*$lm(width)/5)}]
		      ${w}_levelMeter coords mask \
		    ${w}_levelMeter coords mask1 $l2 0 \
			      [expr {$lm(level)*$lm(width)}] 0 \
			      $lm(width) $lm(height)
			$lm(width) $lm(height)
		    ${w}_levelMeter coords mask2 [expr {$l2-5}] 0 \
			$l1 $lm(height)
		  } else {
		    set l1 [expr {5*int($lm(level)*$lm(height)/5)}]
		    set l2 [expr {5*int($lm(maxlevel)*$lm(height)/5)}]
		      ${w}_levelMeter coords mask 0 0 $lm(width) \
			      [expr {$lm(height)-$lm(level)*$lm(height)}]
		    ${w}_levelMeter coords mask1 0 0 $lm(width) \
			[expr {$lm(height)-$l2}]
		    ${w}_levelMeter coords mask2 0 [expr {$lm(height)-$l2+5}] \
			$lm(width) [expr {$lm(height)-$l1}]
		  }	 
	      }
	      -length {
		  if {[string match horiz* $lm(orient)]} {
		      set lm(width) [lindex $args 1]
		  } else {
		      set lm(height) [lindex $args 1]

snack/python/README became executable.

snack/python/tkSnack.py became executable.

Changes to snack/tests/audio.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: snack::audio
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test audio-1.1 {snack::audio command with unknow sub-command} {

Changes to snack/tests/cget.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound cget
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test cget-1.1 {cget command, bad args} {

Changes to snack/tests/concat.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound concatenate
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test concatenate-1.1 {concatenate command} {

Changes to snack/tests/conf.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound configure
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test configure-1.1 {configure command, bad args} {

Changes to snack/tests/convert.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound convert
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test convert-1.1 {convert command, mono->stereo} {

Changes to snack/tests/copy.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound copy
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test copy-1.1 {copy command} {

Changes to snack/tests/crop.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound crop
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test crop-1.1 {crop command} {

Changes to snack/tests/cut.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound cut
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test cut-1.1 {cut command} {

Changes to snack/tests/data.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound data/append
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test data-1.1 {data command, read sound from binary variable} {

Changes to snack/tests/dbpower.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound dBPowerSpectrum
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test dbpower-1.1 {dBPowerSpectrum command} {

Changes to snack/tests/fileio.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound read/write
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test fileio-1.1 {write/read commands for WAV file format} {

Changes to snack/tests/filter.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: snack::filter
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test filter-1.1 {filter command create/destroy} {
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
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







+


-
+







-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







test filter-2.14 {sound filter command, stereo, map filter reconfigured} {
  set s [snack::sound snd -channels 2]
  $s length 1000000
  $s sample 500001 3000 4000
  $s sample 500002 -3000 -4000
  set f [snack::filter map 0.25]
  $s filter $f
  set res [$s max],[$s min]
  $f configure 2.0
  $s filter $f
  set res [$s max],[$s min]
  append res ,[$s max],[$s min]
  $s sample 500001 0 0
  $s sample 500002 0 0
  $s changed New
  append res ,[$s max],[$s min]
  $f destroy
  $s destroy
  set res
} {2000,-2000,0,0}
} {1000,-1000,2000,-2000,0,0}

test filter-2.15 {sound filter command, long sound, check samples} {
  set s [snack::sound snd]
  $s length 200000
  $s sample 100001 3000
  $s sample 100002 -3000
  set f [snack::filter map 0.25]
  $s filter $f -start 100000
  set res [$s max],[$s min]
  $s sample 100001 0
  $s sample 100002 0
  $s changed New
  append res ,[$s max],[$s min]
  $f destroy
  $s destroy
  set res
} {750,-750,0,0}

test filter-3.1 {sound filter command, with -progress option} {
  set res ""
  proc prog {msg frac} {
    lappend ::res $frac
  }
  set s [snack::sound snd]
235
236
237
238
239
240
241
242

243
244
245
246
247
248
249
253
254
255
256
257
258
259

260
261
262
263
264
265
266
267







-
+







  set f2 [snack::filter map 0.5]
  set cf [snack::filter compose $f1 $f2]
  set res $cf
  $f1 destroy
  $f2 destroy
  $cf destroy
  set res
} compose20
} compose21

test filter-4.2 {filter compose, apply three-filter composition} {
  set s [snack::sound snd]
  $s length 10
  $s sample 5 1000
  set f1 [snack::filter map 0.6]
  set f2 [snack::filter map 0.5]
258
259
260
261
262
263
264
265

266
267
268
269
270

271
272
273
274
275

276
277
278
279
280
281
282
276
277
278
279
280
281
282

283
284
285
286
287

288
289
290
291
292

293
294
295
296
297
298
299
300







-
+




-
+




-
+







  $s destroy
  set res
} {120}

test filter-4.3 {filter compose, no filter specified} {
  catch {snack::filter compose} msg
  set msg
} {wrong # args: should be " compose filter1 filter2 ..."}
} {wrong # args: should be "compose filter1 filter2 ..."}

test filter-4.4 {filter compose, only one filter specified} {
  catch {snack::filter compose junk} msg
  set msg
} {wrong # args: should be " compose filter1 filter2 ..."}
} {wrong # args: should be "compose filter1 filter2 ..."}

test filter-5.1 {echo filter, missing parameter} {
  catch {snack::filter echo} msg
  set msg
} {wrong # args: should be " echo inGain outGain delay1 decay1 ..."}
} {wrong # args: should be "echo inGain outGain delay1 decay1 ..."}

test filter-5.2 {echo filter, negative delay parameter} {
  catch {snack::filter echo 0.0 0.0 -100 0} msg
  set msg
} {Delay must be positive}

test filter-5.3 {echo filter, negative decay parameter} {
339
340
341
342
343
344
345





















346
347
348
349
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+




  $f3 destroy
  $f4 destroy
  $g1 destroy
  $c1 destroy
  $s destroy
  set res
} {16000 16000 10026 -6287 Lin16 1 RAW 0}

test filter-7.1 {iir filter, applied to sound} {
  set s [snack::sound snd -load ex1.wav]
  set f [snack::filter iir -numerator "0.99 -0.99" -denominator "1 -0.99"]
  $s filter $f -continuedrain 0
  set res [$s info]
  $f destroy
  $s destroy
  set res
} {15820 16000 13222 -9615 Lin16 1 WAV 44}

test filter-7.2 {iir filter, applied to stereo sound} {
  set s [snack::sound snd -load ex1.wav]
  $s convert -channels 2
  set f [snack::filter iir -numerator "0.99 -0.99" -denominator "1 -0.99"]
  $s filter $f -continuedrain 0
  set res [$s info]
  $f destroy
  $s destroy
  set res
} {15820 16000 13222 -9616 Lin16 2 WAV 44}

# cleanup
::tcltest::cleanupTests
return

Changes to snack/tests/inflush.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound flush info
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test inflush-1.1 {flush/info commands} {

Changes to snack/tests/insert.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound insert
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test insert-1.1 {insert command} {

Changes to snack/tests/length.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound length
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test length-1.1 {length command, get length in samples} {

Changes to snack/tests/maxmin.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound max/min
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test maxmin-1.1 {max/min commands} {

Changes to snack/tests/mixer.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: snack::mixer
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test mixer-1.1 {snack::mixer command} {

Changes to snack/tests/pitch.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound pitch
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test pitch-1.1 {pitch command} {

Changes to snack/tests/play.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound play
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test play-1.1.1 {play command, non-blocking, -load} {
147
148
149
150
151
152
153
































































154
155
156
157
158
159
160
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







  set servsock [socket -server servproc 24683]

  set sock [socket localhost 24683]
  fconfigure $sock -translation binary -blocking 1
  if {$::tcl_version > 8.0} {
    fconfigure $sock -encoding binary
  }
  puts -nonewline $sock $data
  close $sock
 
  vwait flag
  set flag
} RAW

test play-1.1.8 {play command, -channel, data length 0} {
  proc endproc {snd sock} {
    set info [$snd info]
    close $sock
    $snd destroy
    set ::flag [lindex $info 6]
  }
  proc servproc { sock addr port } {
    set s [snack::sound snd -channel $sock -byteorder bigEndian]
    $s play -command [list endproc $s $sock]
  }

  set s [snack::sound snd]
  set data [$s data -fileformat raw -byteorder bigendian]
  $s destroy

  set servsock [socket -server servproc 24684]

  set sock [socket localhost 24684]
  fconfigure $sock -translation binary -blocking 1
  if {$::tcl_version > 8.0} {
    fconfigure $sock -encoding binary
  }
  puts -nonewline $sock $data
  close $sock
 
  vwait flag
  set flag
} RAW

test play-1.1.9 {play command, -channel, data with 1024 initial zeros} {
  proc endproc {snd sock} {
    set info [$snd info]
    close $sock
    $snd destroy
    set ::flag [lindex $info 6]
  }
  proc servproc { sock addr port } {
    set s [snack::sound snd -channel $sock -byteorder bigEndian]
    $s play -command [list endproc $s $sock]
  }

  set s [snack::sound snd -load ex1.wav]
  set s2 [snack::sound snd2]
  $s2 length 512
  set data [$s2 data -fileformat raw -byteorder bigendian]
  append data [$s data -fileformat raw -byteorder bigendian]
  $s destroy
  $s2 destroy

  set servsock [socket -server servproc 24685]

  set sock [socket localhost 24685]
  fconfigure $sock -translation binary -blocking 1
  if {$::tcl_version > 8.0} {
    fconfigure $sock -encoding binary
  }
  puts -nonewline $sock $data
  close $sock
 
  vwait flag
  set flag
} RAW

Added snack/tests/power.test.
















































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# Commands covered: sound power
#

package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test power-1.1 {power command} {
  set s [snack::sound snd -load ex1.wav]
  set tcl_precision 5
  set res [$s power]
  $s destroy
  set res
} {57.668 58.916 57.992 58.647 58.462 58.415 58.353 58.948 58.897 59.02 58.761 58.745 58.248 58.595 59.158 58.846 58.467 61.37 59.153 59.315 58.301 60.035 59.451 58.963 71.281 71.387 71.13 71.213 71.01 70.635 69.845 68.822 68.986 68.525 67.103 66.664 67.365 67.627 66.72 67.337 67.657 68.365 68.854 68.204 58.26 58.141 66.927 69.789 69.122 69.601 69.076 68.909 69.337 68.621 67.11 65.266 64.678 64.223 61.751 60.287 59.447 57.811 58.444 58.209 57.645 57.279 56.377 56.572 56.467 56.796 57.045 57.735 57.858 57.081 56.943 56.421 54.929 56.202 57.349 57.643 57.477 58.207 57.706 58.385 58.601 59.228 58.694 57.176 57.423 57.733 58.599 58.614 58.771 59.005 58.651 59.077 59.001 58.113 58.374}

test power-1.2 {power command} {
  set s [snack::sound snd -load ex1.wav]
  set tcl_precision 5
  set res [$s power -start 4000 -end 4256]
  $s destroy
  set res
} {71.387}

test power-2.1 {power command, with missing argument for -start option} {
  set s [snack::sound snd -load ex1.wav]
  catch {$s power -start} msg
  $s destroy
  set msg
} {No argument given for -start option}

test power-3.1 {power command, -progress option} {
  set res ""
  proc prog {msg frac} {
    lappend ::res [expr 0.1 * int(10*$frac)]
  }
  set s [snack::sound snd -load ex1.wav]
  $s power -progress prog
  $s destroy
  set res
} {0.0 1.0}

# cleanup
::tcltest::cleanupTests
return

Changes to snack/tests/record.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound record/stop
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test record-1.1 {record command} {

Changes to snack/tests/reverse.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound reverse
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test reverse-1.1 {reverse command, ex1.wav} {

Changes to snack/tests/sample.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound sample
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test sample-1.1 {sample command, get} {

Changes to snack/tests/sound.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound creation
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test sound-1.1 {sound command, create with automatic name} {
125
126
127
128
129
130
131
132

133
134
135
136
137
138
139
125
126
127
128
129
130
131

132
133
134
135
136
137
138
139







-
+







  set res
} {0 16000 0 0 Lin16 1 RAW 0}

test sound-4.2 {sound command, two sounds in different interpreters with same name} {
  set s1 [snack::sound snd -load ex1.wav]

  set i [interp create]
  $i eval package require -exact snack 2.0
  $i eval package require -exact snack 2.1
  $i eval snack::sound snd
  $i eval snd destroy
  interp delete $i

  set res [$s info]
  $s destroy
  set res

Changes to snack/tests/swap.test.

1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







# Commands covered: sound swap
#

package require -exact snack 2.0
package require -exact snack 2.1

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import ::tcltest::*
}

test swap-1.1 {swap command} {

Changes to snack/unix/Makefile.in.

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
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







-
+




















-
+
+




-
+







MOZILLA_DIR = @MOZILLA_DIR@

#

GENERIC_DIR = ../generic
UNIX_DIR    = ../unix

VERSION = 2.0
VERSION = 2.1

TCL_VERSION = @TCLVER@

CC        = @CC@

INCLUDES  = ${XINCLUDES} -I${TCL_INCPATH} -I${TK_INCPATH} @AINC@ @NISTINC@

CFLAGS    = -O @CFLAGS@ @AFLAG@ ${INCLUDES} @TCLAPI@ -I${GENERIC_DIR}

LIBSO     = -lc @ALIB@ @TCL_LIB_SPEC@

LIBSN     = -lc @TK_LIBS@ @ALIB@ @TCL_LIB_SPEC@ @TK_LIB_SPEC@

SHLIB_LD     = @SHLIB_LD@
SHLIB_SUFFIX = @SHLIB_SUFFIX@

all: libsound${SHLIB_SUFFIX} libsnack${SHLIB_SUFFIX} @DOSTUBLIB@ @LIBNIST@ editversion

OBJSO = sound.o jkSound.o jkSoundEngine.o jkSoundEdit.o jkSoundFile.o \
	g711.o @AOBJ@ jkFormatMP3.o jkSoundProc.o ffa.o jkPitchCmd.o \
	@STUBINITOBJ@ jkAudio.o jkMixer.o shape.o jkFilter.o jkSynthesis.o
	@STUBINITOBJ@ jkAudio.o jkMixer.o shape.o jkFilter.o jkSynthesis.o \
	jkFilterIIR.o

OBJSN = snack.o jkSound.o jkSoundEngine.o jkSoundEdit.o jkSoundFile.o \
	jkCanvSpeg.o jkCanvWave.o jkCanvSect.o ffa.o g711.o @AOBJ@ \
	jkFormatMP3.o jkSoundProc.o jkPitchCmd.o @STUBINITOBJ@ \
	jkAudio.o jkMixer.o shape.o jkFilter.o jkSynthesis.o
	jkAudio.o jkMixer.o shape.o jkFilter.o jkSynthesis.o jkFilterIIR.o

OBJSNST = snackStubLib.o

sound.o: $(GENERIC_DIR)/sound.c
	$(CC) -c $(CFLAGS) $(GENERIC_DIR)/sound.c

jkSound.o: $(GENERIC_DIR)/jkSound.c
103
104
105
106
107
108
109



110
111
112
113
114
115
116
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120







+
+
+








shape.o: $(GENERIC_DIR)/shape.c
	$(CC) -c $(CFLAGS) $(GENERIC_DIR)/shape.c

jkFilter.o: $(GENERIC_DIR)/jkFilter.c
	$(CC) -c $(CFLAGS) $(GENERIC_DIR)/jkFilter.c

jkFilterIIR.o: $(GENERIC_DIR)/jkFilterIIR.c
	$(CC) -c $(CFLAGS) $(GENERIC_DIR)/jkFilterIIR.c

jkSynthesis.o: $(GENERIC_DIR)/jkSynthesis.c
	$(CC) -c $(CFLAGS) $(GENERIC_DIR)/jkSynthesis.c

snackStubInit.o: $(GENERIC_DIR)/snackStubInit.c
	$(CC) -c $(CFLAGS) $(GENERIC_DIR)/snackStubInit.c

jkAudIO_hp.o: $(UNIX_DIR)/jkAudIO_hp.c
219
220
221
222
223
224
225





















226
227
228
229
230
231
232
233
234
235
236
237
238
239









240
241
242
243
244
245
246
247
248
249
250

251
252
253
254
255
256
257
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+














+
+
+
+
+
+
+
+
+











+







	    chmod 755 dbrec.tcl ;\
	    sed s/wish8.3/wish${TCL_VERSION}/ widget.tcl > tmp ;\
	    mv -f tmp widget.tcl ;\
	    chmod 755 widget.tcl ;\
	    sed s/wish8.3/wish${TCL_VERSION}/ wrap.tcl > tmp ;\
	    mv -f tmp wrap.tcl ;\
	    chmod 755 wrap.tcl ;\
	    sed s/wish8.3/wish${TCL_VERSION}/ generator.tcl > tmp ;\
	    mv -f tmp generator.tcl ;\
	    chmod 755 generator.tcl ;\
	    sed s/wish8.3/wish${TCL_VERSION}/ notescale.tcl > tmp ;\
	    mv -f tmp notescale.tcl ;\
	    chmod 755 notescale.tcl ;\
	    sed s/wish8.3/wish${TCL_VERSION}/ oggstream.tcl > tmp ;\
	    mv -f tmp oggstream.tcl ;\
	    chmod 755 oggstream.tcl ;\
	    sed s/wish8.3/wish${TCL_VERSION}/ polarspec.tcl > tmp ;\
	    mv -f tmp polarspec.tcl ;\
	    chmod 755 polarspec.tcl ;\
	    sed s/wish8.3/wish${TCL_VERSION}/ pitch.tcl > tmp ;\
	    mv -f tmp pitch.tcl ;\
	    chmod 755 pitch.tcl ;\
	    sed s/wish8.3/wish${TCL_VERSION}/ phonetogram.tcl > tmp ;\
	    mv -f tmp phonetogram.tcl ;\
	    chmod 755 phonetogram.tcl ;\
	    sed s/wish8.3/wish${TCL_VERSION}/ CSLwithAB.tcl > tmp ;\
	    mv -f tmp CSLwithAB.tcl ;\
	    chmod 755 CSLwithAB.tcl ;\
	    sed s/wish8.3/wish${TCL_VERSION}/ xs.tcl > tmp ;\
	    mv -f tmp xs.tcl ;\
	    chmod 755 xs.tcl ;\
	    cd ../../unix ;\
	fi
LIBNIST = @NISTLIBS@ -lc @TCL_LIB_SPEC@ -L. @SNACK_STUB_LIB_FLAG@
OBJNIST = SphereFile.o

SphereFile.o: $(GENERIC_DIR)/SphereFile.c
	$(CC) -c $(CFLAGS) -DUSE_SNACK_STUBS $(GENERIC_DIR)/SphereFile.c

libsnacksphere${SHLIB_SUFFIX}: ${OBJNIST}
	${SHLIB_LD} ${OBJNIST} ${LIBNIST} -o libsnacksphere${SHLIB_SUFFIX}

LIBOGG = @OGGLIBS@ -lc @TCL_LIB_SPEC@ -L. @SNACK_STUB_LIB_FLAG@
OBJOGG = SnackOgg.o

SnackOgg.o: $(GENERIC_DIR)/SnackOgg.c
	$(CC) @OGGINC@ -c $(CFLAGS) -DUSE_SNACK_STUBS $(GENERIC_DIR)/SnackOgg.c

libsnackogg${SHLIB_SUFFIX}: ${OBJOGG}
	${SHLIB_LD} ${OBJOGG} ${LIBOGG} -o libsnackogg${SHLIB_SUFFIX}

install:
	@if [ ! -d ${SNACK_INSTALL_PATH}/snack${VERSION} ] ; then \
	    echo "Making directory ${SNACK_INSTALL_PATH}/snack${VERSION}"; \
	    mkdir ${SNACK_INSTALL_PATH}/snack${VERSION}; \
	    chmod 755 ${SNACK_INSTALL_PATH}/snack${VERSION}; \
        else true; \
        fi;
	cp -f libsound${SHLIB_SUFFIX} ${SNACK_INSTALL_PATH}/snack${VERSION}/
	cp -f libsnack${SHLIB_SUFFIX} ${SNACK_INSTALL_PATH}/snack${VERSION}/
	if test -f libsnackstub${VERSION}.a; then cp -f libsnackstub${VERSION}.a ${SNACK_INSTALL_PATH}/; fi
	if test -f libsnacksphere${SHLIB_SUFFIX}; then cp -f libsnacksphere${SHLIB_SUFFIX} ${SNACK_INSTALL_PATH}/snack${VERSION}/; fi
	if test -f libsnackogg${SHLIB_SUFFIX}; then cp -f libsnackogg${SHLIB_SUFFIX} ${SNACK_INSTALL_PATH}/snack${VERSION}/; fi
	cp -f snack.tcl ${SNACK_INSTALL_PATH}/snack${VERSION}/
	cp -f pkgIndex.tcl ${SNACK_INSTALL_PATH}/snack${VERSION}/
	@if [ -d "@MOZILLA_DIR@" ] ; then \
	    cp -rf ${SNACK_INSTALL_PATH}/snack${VERSION} ${MOZILLA_DIR}/tclplug/2.0/; \
	fi;

clean:

Changes to snack/unix/configure.

16
17
18
19
20
21
22


23





24
25
26
27
28
29
30
16
17
18
19
20
21
22
23
24

25
26
27
28
29
30
31
32
33
34
35
36







+
+
-
+
+
+
+
+







ac_help="$ac_help
  --with-tk               directory containing tk configuration (tkConfig.sh)"
ac_help="$ac_help
  --enable-plugin         enable plug-in"
ac_help="$ac_help
  --with-mozilla=DIR      will install in DIR/tclplug/2.0/"
ac_help="$ac_help
  --with-nist-include=DIR use NIST/SPHERE includes in DIR"
ac_help="$ac_help
  --with-nist=DIR         use NIST/SPHERE libraries from DIR"
  --with-nist-lib=DIR     use NIST/SPHERE libraries in DIR"
ac_help="$ac_help
  --with-ogg-include=DIR  use Ogg/Vorbis includes in DIR"
ac_help="$ac_help
  --with-ogg-lib=DIR      use Ogg/Vorbis libraries in DIR"
ac_help="$ac_help
  --disable-stubs         disable stub support"

# Initialize some variables set by options.
# The variables have the same names as the options, with
# dashes changed to underlines.
build=NONE
530
531
532
533
534
535
536
537

538
539
540
541
542
543
544
536
537
538
539
540
541
542

543
544
545
546
547
548
549
550







-
+







  fi
else
  ac_n= ac_c='\c' ac_t=
fi



SNACK_VERSION=2.0
SNACK_VERSION=2.1

#--------------------------------------------------------------------
#       See if there was a command-line option for where Tcl is;  if
#       not, assume that its top-level directory is a sibling of ours.
#--------------------------------------------------------------------


554
555
556
557
558
559
560
561

562
563
564
565
566
567
568
560
561
562
563
564
565
566

567
568
569
570
571
572
573
574







-
+







	# Check whether --with-tcl or --without-tcl was given.
if test "${with_tcl+set}" = set; then
  withval="$with_tcl"
  with_tclconfig=${withval}
fi

	echo $ac_n "checking for Tcl configuration""... $ac_c" 1>&6
echo "configure:562: checking for Tcl configuration" >&5
echo "configure:568: checking for Tcl configuration" >&5
	if eval "test \"`echo '$''{'ac_cv_c_tclconfig'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else
  

	    # First check to see if --with-tcl was specified.
	    if test x"${with_tclconfig}" != x ; then
645
646
647
648
649
650
651
652

653
654
655
656
657
658
659
651
652
653
654
655
656
657

658
659
660
661
662
663
664
665







-
+







	# Check whether --with-tk or --without-tk was given.
if test "${with_tk+set}" = set; then
  withval="$with_tk"
  with_tkconfig=${withval}
fi

	echo $ac_n "checking for Tk configuration""... $ac_c" 1>&6
echo "configure:653: checking for Tk configuration" >&5
echo "configure:659: checking for Tk configuration" >&5
	if eval "test \"`echo '$''{'ac_cv_c_tkconfig'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else
  

	    # First check to see if --with-tkconfig was specified.
	    if test x"${with_tkconfig}" != x ; then
717
718
719
720
721
722
723



724
725
726


727
728
729
730
731
732
733
723
724
725
726
727
728
729
730
731
732
733


734
735
736
737
738
739
740
741
742







+
+
+

-
-
+
+









#--------------------------------------------------------------------

if test "x${prefix}" = "xNONE"; then
    prefix=/usr/local
fi
if test "x${exec_prefix}" = "xNONE"; then
    exec_prefix=$prefix
fi

SNACK_INSTALL_PATH=${prefix}/lib
SNACK_LIB_SPEC="-L${prefix}/lib -lsnack"
SNACK_INSTALL_PATH=${exec_prefix}/lib
SNACK_LIB_SPEC="-L${exec_prefix}/lib -lsnack"

#--------------------------------------------------------------------
#       Read in configuration information generated by Tcl and
#	arrange for it to be substituted into our Makefile.
#--------------------------------------------------------------------

file=$TCL_BIN_DIR/tclConfig.sh
767
768
769
770
771
772
773
774

775
776
777
778
779
780
781
782
783

784
785
786
787
788
789
790
776
777
778
779
780
781
782

783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800







-
+









+








case $system in
    BSD/OS-4.*)
	AFLAG="-DOSS"
	ALIB="-lossaudio"
	AOBJ="jkAudIO_oss.o"
        ;;
    HP-UX-*.10.*)
    HP-UX-*.1*)
	if test "$CC" = "gcc" -o `$CC -v 2>&1 | grep -c gcc` != "0" ; then
	    CFLAGS=$CFLAGS
	else
	    CFLAGS="-Ae +z"
	fi
	AINC="-I/opt/audio/include"
	AFLAG="-DHPUX"
	ALIB="-L/opt/audio/lib -lAlib"
	AOBJ="jkAudIO_hp.o"
	SHLIB_LD="$SHLIB_LD +s"
	;;
    IRIX*)
	AFLAG="-DIRIX"
        ALIB="-laudio"
	AOBJ="jkAudIO_sgi.o"
	;;
    IRIX64-6.*)
827
828
829
830
831
832
833
834

835
836
837
838
839
840
841
837
838
839
840
841
842
843

844
845
846
847
848
849
850
851







-
+







else
  enableval="no"
fi


if test "$enableval" != "no"; then
  echo $ac_n "checking Mozilla Home""... $ac_c" 1>&6
echo "configure:835: checking Mozilla Home" >&5
echo "configure:844: checking Mozilla Home" >&5
# Check for Mozilla home (install directory of netscape (plugins))
  # Check whether --with-mozilla or --without-mozilla was given.
if test "${with_mozilla+set}" = set; then
  withval="$with_mozilla"
  MOZILLA_DIR=$withval
else
  MOZILLA_DIR="$MOZILLA_HOME"
854
855
856
857
858
859
860
861
862
863
864
865




866
867

868
869
870
871
872
















873
874


875



876























877
878
879

880
881
882
883
884
885
886
864
865
866
867
868
869
870





871
872
873
874
875

876
877
878



879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928

929
930
931
932
933
934
935
936







-
-
-
-
-
+
+
+
+

-
+


-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


+
+

+
+
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


-
+







fi

#--------------------------------------------------------------------
#	Get the path to the NIST/SPHERE distribution. This is
#	only necessary if you want to build the NIST package.
#--------------------------------------------------------------------

LIBNIST=""
# Check whether --with-nist or --without-nist was given.
if test "${with_nist+set}" = set; then
  withval="$with_nist"
  NIST_DIR=$withval
# Check whether --with-nist-include or --without-nist-include was given.
if test "${with_nist_include+set}" = set; then
  withval="$with_nist_include"
  NIST_INC_DIR=$withval
else
  NIST_DIR=""
  NIST_INC_DIR=""
fi

NISTINC="-I$NIST_DIR/include"
NISTLIBS="$NIST_DIR/lib/libsp.a $NIST_DIR/lib/libutil.a"
if test ! "$NIST_DIR" = ""; then
NISTINC="-I$NIST_INC_DIR"
if test "$NISTINC" = "-I"; then
  NISTINC=""
fi

# Check whether --with-nist-lib or --without-nist-lib was given.
if test "${with_nist_lib+set}" = set; then
  withval="$with_nist_lib"
  NIST_LIB_DIR=$withval
else
  NIST_LIB_DIR=""
fi

NISTLIBS="$NIST_LIB_DIR/libsp.a $NIST_LIB_DIR/libutil.a"
LIBNIST=""
if test ! "$NIST_LIB_DIR" = ""; then
  LIBNIST="libsnacksphere${SHLIB_SUFFIX}"
fi


#--------------------------------------------------------------------
#	Get the path to the Ogg/Vorbis installation. This is
#	only necessary if you want to build the snackogg package.
#--------------------------------------------------------------------

LIBOGG=""
# Check whether --with-ogg-include or --without-ogg-include was given.
if test "${with_ogg_include+set}" = set; then
  withval="$with_ogg_include"
  OGG_INC_DIR=$withval
else
  OGG_INC_DIR=""
fi

# Check whether --with-ogg-lib or --without-ogg-lib was given.
if test "${with_ogg_lib+set}" = set; then
  withval="$with_ogg_lib"
  OGG_LIB_DIR=$withval
else
  OGG_LIB_DIR=""
fi

OGGINC="-I$OGG_INC_DIR"
OGGLIBS="-L$OGG_LIB_DIR -lvorbisenc -lvorbis -logg"
if test ! "$OGG_LIB_DIR" = ""; then
  LIBOGG="libsnackogg${SHLIB_SUFFIX}"
fi

#--------------------------------------------------------------------
#	Disable stub support. This is necessary if you
#	want to run Snack with Tcl/Tk 8.0 up to 8.0.5
#	want to run Snack with Tcl/Tk versions 8.0 through 8.0.5
#--------------------------------------------------------------------

# Check whether --enable-stubs or --disable-stubs was given.
if test "${enable_stubs+set}" = set; then
  enableval="$enable_stubs"
  :
else
906
907
908
909
910
911
912



913
914
915
916
917
918
919
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972







+
+
+







    else
	STUBINITOBJ=""
    fi
    DOSTUBLIB=""
    SNIST_LIB_SPEC="-lsnack"
fi
#--------------------------------------------------------------------










1097
1098
1099
1100
1101
1102
1103



1104
1105
1106
1107
1108
1109
1110
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166







+
+
+







s%@AINC@%$AINC%g
s%@AFLAG@%$AFLAG%g
s%@ALIB@%$ALIB%g
s%@AOBJ@%$AOBJ%g
s%@NISTINC@%$NISTINC%g
s%@NISTLIBS@%$NISTLIBS%g
s%@LIBNIST@%$LIBNIST%g
s%@OGGINC@%$OGGINC%g
s%@OGGLIBS@%$OGGLIBS%g
s%@LIBOGG@%$LIBOGG%g
s%@TCLAPI@%$TCLAPI%g
s%@LD_SEARCH_FLAGS@%$LD_SEARCH_FLAGS%g
s%@TCLVER@%$TCLVER%g
s%@STUBINITOBJ@%$STUBINITOBJ%g
s%@DOSTUBLIB@%$DOSTUBLIB%g
s%@SNACK_STUB_LIB_FLAG@%$SNACK_STUB_LIB_FLAG%g
s%@SNACK_VERSION@%$SNACK_VERSION%g

Changes to snack/unix/configure.in.

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
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






-
+




















+
+
+

-
-
+
+







#! /bin/bash -norc
dnl	This file is an input file used by the GNU "autoconf" program to
dnl	generate the file "configure", which is run during Snack installation
dnl	to configure the system for the local environment.
AC_INIT(../generic/snack.h)

SNACK_VERSION=2.0
SNACK_VERSION=2.1

#--------------------------------------------------------------------
#       See if there was a command-line option for where Tcl is;  if
#       not, assume that its top-level directory is a sibling of ours.
#--------------------------------------------------------------------

SC_PATH_TCLCONFIG

#--------------------------------------------------------------------
#       See if there was a command-line option for where Tk is;  if
#       not, assume that its top-level directory is a sibling of ours.
#--------------------------------------------------------------------

SC_PATH_TKCONFIG

#--------------------------------------------------------------------

if test "x${prefix}" = "xNONE"; then
    prefix=/usr/local
fi
if test "x${exec_prefix}" = "xNONE"; then
    exec_prefix=$prefix
fi

SNACK_INSTALL_PATH=${prefix}/lib
SNACK_LIB_SPEC="-L${prefix}/lib -lsnack"
SNACK_INSTALL_PATH=${exec_prefix}/lib
SNACK_LIB_SPEC="-L${exec_prefix}/lib -lsnack"

#--------------------------------------------------------------------
#       Read in configuration information generated by Tcl and
#	arrange for it to be substituted into our Makefile.
#--------------------------------------------------------------------

file=$TCL_BIN_DIR/tclConfig.sh
71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
86
87

88
89
90
91
92
93
94
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







-
+









+








case $system in
    BSD/OS-4.*)
	AFLAG="-DOSS"
	ALIB="-lossaudio"
	AOBJ="jkAudIO_oss.o"
        ;;
    HP-UX-*.10.*)
    HP-UX-*.1*)
	if test "$CC" = "gcc" -o `$CC -v 2>&1 | grep -c gcc` != "0" ; then
	    CFLAGS=$CFLAGS
	else
	    CFLAGS="-Ae +z"
	fi
	AINC="-I/opt/audio/include"
	AFLAG="-DHPUX"
	ALIB="-L/opt/audio/lib -lAlib"
	AOBJ="jkAudIO_hp.o"
	SHLIB_LD="$SHLIB_LD +s"
	;;
    IRIX*)
	AFLAG="-DIRIX"
        ALIB="-laudio"
	AOBJ="jkAudIO_sgi.o"
	;;
    IRIX64-6.*)
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
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







-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+


+
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+



-
+







fi

#--------------------------------------------------------------------
#	Get the path to the NIST/SPHERE distribution. This is
#	only necessary if you want to build the NIST package.
#--------------------------------------------------------------------

LIBNIST=""
AC_ARG_WITH(nist,[  --with-nist=DIR         use NIST/SPHERE libraries from DIR],
        NIST_DIR=$withval, NIST_DIR="")
NISTINC="-I$NIST_DIR/include"
NISTLIBS="$NIST_DIR/lib/libsp.a $NIST_DIR/lib/libutil.a"
if test ! "$NIST_DIR" = ""; then
AC_ARG_WITH(nist-include,[  --with-nist-include=DIR use NIST/SPHERE includes in DIR],
        NIST_INC_DIR=$withval, NIST_INC_DIR="")
NISTINC="-I$NIST_INC_DIR"
if test "$NISTINC" = "-I"; then
  NISTINC=""
fi

AC_ARG_WITH(nist-lib,[  --with-nist-lib=DIR     use NIST/SPHERE libraries in DIR],
        NIST_LIB_DIR=$withval, NIST_LIB_DIR="")
NISTLIBS="$NIST_LIB_DIR/libsp.a $NIST_LIB_DIR/libutil.a"
LIBNIST=""
if test ! "$NIST_LIB_DIR" = ""; then
  LIBNIST="libsnacksphere${SHLIB_SUFFIX}"
fi


#--------------------------------------------------------------------
#	Get the path to the Ogg/Vorbis installation. This is
#	only necessary if you want to build the snackogg package.
#--------------------------------------------------------------------

LIBOGG=""
AC_ARG_WITH(ogg-include,[  --with-ogg-include=DIR  use Ogg/Vorbis includes in DIR],
        OGG_INC_DIR=$withval, OGG_INC_DIR="")
AC_ARG_WITH(ogg-lib,[  --with-ogg-lib=DIR      use Ogg/Vorbis libraries in DIR],
        OGG_LIB_DIR=$withval, OGG_LIB_DIR="")
OGGINC="-I$OGG_INC_DIR"
OGGLIBS="-L$OGG_LIB_DIR -lvorbisenc -lvorbis -logg"
if test ! "$OGG_LIB_DIR" = ""; then
  LIBOGG="libsnackogg${SHLIB_SUFFIX}"
fi

#--------------------------------------------------------------------
#	Disable stub support. This is necessary if you
#	want to run Snack with Tcl/Tk 8.0 up to 8.0.5
#	want to run Snack with Tcl/Tk versions 8.0 through 8.0.5
#--------------------------------------------------------------------

AC_ARG_ENABLE(stubs,[  --disable-stubs         disable stub support],,enableval2="no")

if test "$enableval2" = "no"; then
    AC_MSG_RESULT(will use stubs (normal))
    CFLAGS="$CFLAGS -DUSE_TCL_STUBS -DUSE_TK_STUBS"
203
204
205
206
207
208
209



210
211
212
213
214
215
216
217
218
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247







+
+
+









AC_SUBST(AINC)
AC_SUBST(AFLAG)
AC_SUBST(ALIB)
AC_SUBST(AOBJ)
AC_SUBST(NISTINC)
AC_SUBST(NISTLIBS)
AC_SUBST(LIBNIST)
AC_SUBST(OGGINC)
AC_SUBST(OGGLIBS)
AC_SUBST(LIBOGG)
AC_SUBST(TCLAPI)
AC_SUBST(LD_SEARCH_FLAGS)
AC_SUBST(TCLVER)
AC_SUBST(STUBINITOBJ)
AC_SUBST(DOSTUBLIB)
AC_SUBST(SNACK_STUB_LIB_FLAG)
AC_SUBST(SNACK_VERSION)

AC_OUTPUT(Makefile snackConfig.sh)

Changes to snack/unix/jkAudIO_hp.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
80
81
82
83
84
85
86
87




88
89
90
91
92
93
94
80
81
82
83
84
85
86

87
88
89
90
91
92
93
94
95
96
97







-
+
+
+
+







  long            status;
  int             n = 0;

  if (A->debug > 1) Snack_WriteLog("  Enter SnackAudioOpen\n");

  ASetErrorHandler(newHandler);

  A->audio = AOpenAudio(NULL, NULL);
  if ((A->audio = AOpenAudio(NULL, NULL)) == NULL) {
    Tcl_AppendResult(interp, "Audio server not active (AOpenAudio returns NULL).", NULL);
    return TCL_ERROR;
  }

  attribs.type = ATSampled;
  attribs.attr.sampled_attr.sampling_rate = freq;
  attribs.attr.sampled_attr.channels = nchannels;
  A->nChannels = nchannels;
  A->convert = 0;

389
390
391
392
393
394
395


396
397
398
399
400
401
402
403
404
405
406


407
408
409
410
411
412
413
414
415
416
417



418
419
420
421
422
423
424
425
426
427
428
429



430
431
432
433
434
435
436
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423

424
425
426
427
428
429
430
431
432
433
434
435
436
437

438
439
440
441
442
443
444
445
446
447







+
+











+
+










-
+
+
+











-
+
+
+







  }
}

void
ASetRecGain(int gain)
{
  int g = min(max(gain, 0), 100);

  if (a == NULL) return;

  g = (int) (g * (a->max_input_gain - a->min_input_gain) / 100.0 + a->min_input_gain + 0.5);

  ASetSystemRecordGain(a, g, (long *)NULL);
  ASetSystemChannelGain(a, ASGTRecord, ACTMono, g, (long *)NULL);
}

void
ASetPlayGain(int gain)
{
  int g = min(max(gain, 0), 100);

  if (a == NULL) return;

  g = (int) (g * (a->max_output_gain - a->min_output_gain) / 100.0 + a->min_output_gain);

  ASetSystemChannelGain(a, ASGTPlay, ACTMono, g, (long *)NULL);
}

int
AGetRecGain()
{
  long g = 0;

  
  if (a == NULL) return(0);
  
  AGetSystemChannelGain(a, ASGTRecord, ACTMono, &g, (long *)NULL);

  g = (int) ((g - a->min_input_gain) * 100.0 / (a->max_input_gain - a->min_input_gain) + 0.5);

  return(g);
}

int
AGetPlayGain()
{
  long g = 0;

  
  if (a == NULL) return(0);
  
  AGetSystemChannelGain(a, ASGTPlay, ACTMono, &g, (long *)NULL);

  g = (int) ((g - a->min_output_gain) * 100.0 / (a->max_output_gain - a->min_output_gain));

  return(g);
}

448
449
450
451
452
453
454






455
456
457
458
459
460
461
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478







+
+
+
+
+
+







}

int
SnackAudioMaxNumberChannels(char *device)
{
  return(2);
}

int
SnackAudioMinNumberChannels(char *device)
{
  return(1);
}

void
SnackMixerGetInputJackLabels(char *buf, int n)
{
  strncpy(buf, "Microphone \"Line In\"", n);
  buf[n-1] = '\0';
}

Changes to snack/unix/jkAudIO_oss.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
47
48
49
50
51
52
53


54
55
56
57
58
59
60
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62







+
+







#endif

static int mfd = 0;

static struct MixerLink mixerLinks[SOUND_MIXER_NRDEVICES][2];

static int littleEndian = 0;

static int minNumChan = 1;

int
SnackAudioOpen(ADesc *A, Tcl_Interp *interp, char *device, int mode, int freq,
	       int nchannels, int encoding)
{
  int format;
  int nformat;
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
172
173
174
175
176
177
178

179
180
181
182
183
184
185







-







  speed = freq;
  if (ioctl(A->afd, SNDCTL_DSP_SPEED, &speed) == -1
      || abs(speed - freq) > freq / 100) {
    close(A->afd);
    Tcl_AppendResult(interp, "Failed setting sample frequency.", NULL);
    return TCL_ERROR;
  }

  
  /*  A->count = 0;*/
  A->frag_size = 0;
  if (ioctl(A->afd, SNDCTL_DSP_GETBLKSIZE, &A->frag_size) == -1) {
    close(A->afd);
    Tcl_AppendResult(interp, "Failed getting fragment size.", NULL);
    return TCL_ERROR;
374
375
376
377
378
379
380

381
382
383
384
385
386
387
388
389
390
391






















392
393
394
395
396
397
398
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422







+











+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







void
SnackAudioInit()
{
  union {
    char c[sizeof(short)];
    short s;
  } order;
  int afd, format, channels, nchannels;

  /* Compute the byte order of this machine. */

  order.s = 1;
  if (order.c[0] == 1) {
    littleEndian = 1;
  }

  if ((mfd = open(MIXER_NAME, O_RDWR, 0)) == -1) {
    fprintf(stderr, "Unable to open mixer %s\n", MIXER_NAME);
  }

  /* Determine minimum number of channels supported. */
  
  if ((afd = open(defaultDeviceName, O_WRONLY, 0)) == -1) {
    return;
  }
  
  if (littleEndian) {
    format = AFMT_S16_LE;
  } else {
    format = AFMT_S16_BE;
  }
  if (ioctl(afd, SNDCTL_DSP_SETFMT, &format) == -1) {
    close(afd);
    return;
  }
  channels = nchannels = 1;
  if (ioctl(afd, SNDCTL_DSP_CHANNELS, &channels) == -1
      || channels != nchannels) {
    minNumChan = channels;
  }
  close(afd);
}

void
SnackAudioFree()
{
  int i, j;

493
494
495
496
497
498
499
500

501
502
503
504
505
506

507
508
509
510
511
512
513
514
515
516
517
518
519






520
521
522
523
524
525
526
517
518
519
520
521
522
523

524
525
526
527
528
529

530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556







-
+





-
+













+
+
+
+
+
+







  }
}

void
SnackAudioGetRates(char *device, char *buf, int n)
{
  int afd, freq, pos= 0, i;
  int f[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000 };
  int f[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 96000 };

  if ((afd = open(DEVICE_NAME, O_WRONLY, 0)) == -1) {
    buf[0] = '\0';
    return;
  }
  for (i = 0; i < 7; i++) {
  for (i = 0; i < 8; i++) {
    freq = f[i];
    if (ioctl(afd, SNDCTL_DSP_SPEED, &freq) == -1) break;
    if (abs(f[i] - freq) > freq / 100) continue;
    pos += sprintf(&buf[pos], "%d ", freq);
  }
  close(afd);
}

int
SnackAudioMaxNumberChannels(char *device)
{
  return(2);
}

int
SnackAudioMinNumberChannels(char *device)
{
  return(minNumChan);
}

void
SnackMixerGetInputJackLabels(char *buf, int n)
{
  char *jackLabels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS;
  int i, recMask, pos = 0;

917
918
919
920
921
922
923


924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941

942

943
944
945
946
947
948
949
950
951
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974

975
976
977
978
979
980
981
982
983
984







+
+


















+
-
+









SnackGetInputDevices(char **arr, int n)
{
  int i, j = 0;
  glob_t globt;
  
  glob("/dev/dsp*", 0, NULL, &globt);
  glob("/dev/audio*", GLOB_APPEND, NULL, &globt);
  glob("/dev/sound/dsp*", GLOB_APPEND, NULL, &globt);
  glob("/dev/sound/audio*", GLOB_APPEND, NULL, &globt);

  for (i = 0; i < globt.gl_pathc; i++) {
    if (j < n) {
      arr[j++] = (char *) SnackStrDup(globt.gl_pathv[i]);
    }
  }
  globfree(&globt);

  return(j);
}

int
SnackGetMixerDevices(char **arr, int n)
{
  int i, j = 0;
  glob_t globt;
  
  glob("/dev/mixer*", 0, NULL, &globt);
  glob("/dev/sound/mixer*", GLOB_APPEND, NULL, &globt);

  
  for (i = 0; i < globt.gl_pathc; i++) {
    if (j < n) {
      arr[j++] = (char *) SnackStrDup(globt.gl_pathv[i]);
    }
  }
  globfree(&globt);

  return(j);
}

Changes to snack/unix/jkAudIO_sgi.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
468
469
470
471
472
473
474
475







476
477
478
479
480
481
482
468
469
470
471
472
473
474

475
476
477
478
479
480
481
482
483
484
485
486
487
488







-
+
+
+
+
+
+
+







  strncpy(buf, "8000 11025 16000 22050 32000 44100 48000", n);
  buf[n-1] = '\0';
}

int
SnackAudioMaxNumberChannels(char *device)
{
  return(8);
  return(16);
}

int
SnackAudioMinNumberChannels(char *device)
{
  return(1);
}

void
SnackMixerGetInputJackLabels(char *buf, int n)
{
  strncpy(buf, "Microphone \"Line In\"", n);
  buf[n-1] = '\0';

Changes to snack/unix/jkAudIO_skel.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
167
168
169
170
171
172
173






174
175
176
177
178
179
180
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186







+
+
+
+
+
+







}

int
SnackAudioMaxNumberChannels(char *device)
{
  return(2);
}

int
SnackAudioMinNumberChannels(char *device)
{
  return(1);
}

void
SnackMixerGetInputJackLabels(char *buf, int n)
{
  buf[0] = '\0';
}

Changes to snack/unix/jkAudIO_sun.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
396
397
398
399
400
401
402






403
404
405
406
407
408
409
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415







+
+
+
+
+
+







}

int
SnackAudioMaxNumberChannels(char *device)
{
  return(2);
}

int
SnackAudioMinNumberChannels(char *device)
{
  return(1);
}

void
SnackMixerGetInputJackLabels(char *buf, int n)
{
  strncpy(buf, "Microphone \"Line In\"", n);
  buf[n-1] = '\0';
}

Changes to snack/unix/pkgIndex.tcl.dll.

1
2
3
4

5
6
7

8
9

10
11



1
2
3

4
5
6

7
8

9
10

11
12
13



-
+


-
+

-
+

-
+
+
+
#
# Immediate loading of Snack because of item types etc.
#
# http://www.cogent.net/~duquette/tcl/namespaces.html
# http://www.wjduquette.com/tcl/namespaces.html
#

package ifneeded snack 2.0 "[list load [file join $dir libsnack.dll]];[list source [file join $dir snack.tcl]]"
package ifneeded snack 2.1 "[list load [file join $dir libsnack.dll]];[list source [file join $dir snack.tcl]]"

package ifneeded sound 2.0 [list load [file join $dir libsound.dll]]
package ifneeded sound 2.1 [list load [file join $dir libsound.dll]]

package ifneeded snacksphere 1.0 [list load [file join $dir libsnacksphere.dll]]
package ifneeded snacksphere 1.2 [list load [file join $dir libsnacksphere.dll]]

package ifneeded snackogg 1.1 [list load [file join $dir libsnackogg.dll]]

Changes to snack/unix/snack.tcl.

15
16
17
18
19
20
21
22

23
24
25
26
27
28
29
15
16
17
18
19
20
21

22
23
24
25
26
27
28
29







-
+







# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

package provide snack 2.0
package provide snack 2.1

# Set playback latency according to the environment variable PLAYLATENCY

if {$::tcl_platform(platform) == "unix"} {
    if {[info exists env(PLAYLATENCY)] && $env(PLAYLATENCY) > 0} {
	snack::audio playLatency $env(PLAYLATENCY)
    }
108
109
110
111
112
113
114
115

116
117
118
119
120
121
122
108
109
110
111
112
113
114

115
116
117
118
119
120
121
122







-
+







			-variable [namespace current]::v(in$jack)] \
			-anchor w
	    }
	}
	if {[snack::mixer outputs] != ""} {
	    pack [label $wi.f.f2.lo -text "Output jacks:"]
	    foreach jack [snack::mixer outputs] {
		snack::mixer lines $jack [namespace current]::v(out$jack)
		snack::mixer output $jack [namespace current]::v(out$jack)
		pack [checkbutton $wi.f.f2.b$jack -text $jack \
			-variable [namespace current]::v(out$jack)] \
			-anchor w
	    }
	}
	pack [button $wi.b1 -text Close -command "destroy $wi"]
    }
247
248
249
250
251
252
253








254





255
256
257
258
259
260
261
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261

262
263
264
265
266
267
268
269
270
271
272
273







+
+
+
+
+
+
+
+
-
+
+
+
+
+







	if {$data(-format) == ""} {
	    set data(-format) RAW
	}
	set data(-format) [string toupper $data(-format)]
	if {$data(-initialdir) == ""} {
	    set data(-initialdir) "."
	}
	if {[string match macintosh $::tcl_platform(platform)]} {
	  set tmp [tk_getSaveFile -title $data(-title) \
	      -initialdir $data(-initialdir) -initialfile $data(-initialfile)]
	  if {[string compare [file ext $tmp] ""] == 0} {
	    append tmp [fmt2ext $data(-format)]
	  }
	  return $tmp
	} else {
	return [tk_getSaveFile -title $data(-title) -filetypes [saveTypes $data(-format)] -defaultextension [fmt2ext $data(-format)] -initialdir $data(-initialdir) -initialfile $data(-initialfile)]
	  return [tk_getSaveFile -title $data(-title) \
	      -filetypes [saveTypes $data(-format)] \
	      -defaultextension [fmt2ext $data(-format)] \
	      -initialdir $data(-initialdir) -initialfile $data(-initialfile)]
	}
    }

    set saveTypes ""

    proc addSaveTypes {typelist fmtlist} {
	variable saveTypes
	variable filebox
1092
1093
1094
1095
1096
1097
1098


1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110



1111
1112
1113
1114



1115
1116
1117
1118
1119
1120
1121



1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140










1141


1142

1143
1144



1145


1146
1147




1148
1149
1150
1151
1152
1153
1154
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123

1124
1125
1126
1127
1128
1129

1130
1131
1132
1133
1134
1135
1136
1137
1138

1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157



1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170

1171


1172
1173
1174
1175
1176
1177


1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188







+
+











-
+
+
+



-
+
+
+






-
+
+
+
















-
-
-
+
+
+
+
+
+
+
+
+
+

+
+
-
+
-
-
+
+
+

+
+
-
-
+
+
+
+







	if {[string match horiz* $lm(orient)]} {
	    set lm(height) $a(-width)
	    set lm(width)  $a(-length)
	} else {
	    set lm(height) $a(-length)
	    set lm(width)  $a(-width)
	}
	set lm(maxtime) [clock seconds]
	set lm(maxlevel) 0.0

	proc drawLevelMeter {w} {
            upvar [namespace current]::${w}::levelmeter lm

	    set c ${w}_levelMeter
	    $c configure -width $lm(width) -height $lm(height)
	    $c delete all

	    $c create rectangle 0 0 $lm(width) $lm(height) \
		    -fill $lm(oncolor) -outline ""
	    $c create rectangle 0 0 0 0 -outline "" -fill $lm(offcolor) \
		    -tag mask
		    -tag mask1
	    $c create rectangle 0 0 0 0 -outline "" -fill $lm(offcolor) \
		    -tag mask2
	    $c create rectangle 0 0 [expr $lm(width)-1] [expr $lm(height)-1] \
		    -outline $lm(bg)
	    if {[string match horiz* $lm(orient)]} {
		$c coords mask [expr {$lm(level)*$lm(width)}] 0 \
		$c coords mask1 [expr {$lm(level)*$lm(width)}] 0 \
			$lm(width) $lm(height)
		$c coords mask2 [expr {$lm(level)*$lm(width)}] 0 \
			$lm(width) $lm(height)
		for {set x 5} {$x < $lm(width)} {incr x 5} {
		    $c create line $x 0 $x [expr $lm(width)-1] -fill black \
			    -width 2
		}
	    } else {
		$c coords mask 0 0 $lm(width) \
		$c coords mask1 0 0 $lm(width) \
			[expr {$lm(height)-$lm(level)*$lm(height)}]
		$c coords mask2 0 0 $lm(width) \
			[expr {$lm(height)-$lm(level)*$lm(height)}]
		for {set y 5} {$y < $lm(height)} {incr y 5} {
		    $c create line 0 [expr $lm(height)-$y] \
			    [expr $lm(width)-1] [expr $lm(height)-$y] \
			    -fill black -width 2
		}
	    }
	}

	proc levelMeterHandler {w cmd args} {
          upvar [namespace current]::${w}::levelmeter lm

          if {[string match conf* $cmd]} {
              switch -- [lindex $args 0] {
    	      -level {
		  set arg [lindex $args 1]
		  set arg [expr {$arg/32768.0}]
		  if {$arg < 0.00001} { set arg 0.00001 }
		  set lm(level) [expr {log($arg)/4.516+1.0}]
   		  if {$arg < 1} { set arg 1 }
		  set lm(level) [expr {log($arg)/10.3972}]
		  if {[clock seconds] - $lm(maxtime) > 2} {
		    set lm(maxtime) [clock seconds]
		    set lm(maxlevel) 0.0
		  }
		  if {$lm(level) > $lm(maxlevel)} {
		    set lm(maxlevel) $lm(level)
		  }

		  if {[string match horiz* $lm(orient)]} {
		    set l1 [expr {5*int($lm(level)*$lm(width)/5)}]
		    set l2 [expr {5*int($lm(maxlevel)*$lm(width)/5)}]
		      ${w}_levelMeter coords mask \
		    ${w}_levelMeter coords mask1 $l2 0 \
			      [expr {$lm(level)*$lm(width)}] 0 \
			      $lm(width) $lm(height)
			$lm(width) $lm(height)
		    ${w}_levelMeter coords mask2 [expr {$l2-5}] 0 \
			$l1 $lm(height)
		  } else {
		    set l1 [expr {5*int($lm(level)*$lm(height)/5)}]
		    set l2 [expr {5*int($lm(maxlevel)*$lm(height)/5)}]
		      ${w}_levelMeter coords mask 0 0 $lm(width) \
			      [expr {$lm(height)-$lm(level)*$lm(height)}]
		    ${w}_levelMeter coords mask1 0 0 $lm(width) \
			[expr {$lm(height)-$l2}]
		    ${w}_levelMeter coords mask2 0 [expr {$lm(height)-$l2+5}] \
			$lm(width) [expr {$lm(height)-$l1}]
		  }	 
	      }
	      -length {
		  if {[string match horiz* $lm(orient)]} {
		      set lm(width) [lindex $args 1]
		  } else {
		      set lm(height) [lindex $args 1]

Changes to snack/win/jkAudIO_win.c.

1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/* 
 * Copyright (C) 1997-2001 Kare Sjolander <kare@speech.kth.se>
 * Copyright (C) 1997-2002 Kare Sjolander <kare@speech.kth.se>
 *
 * This file is part of the Snack Sound Toolkit.
 * The latest version can be found at http://www.speech.kth.se/snack/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
1339
1340
1341
1342
1343
1344
1345
1346

1347
1348
1349
1350
1351
1352
1353
1339
1340
1341
1342
1343
1344
1345

1346
1347
1348
1349
1350
1351
1352
1353







-
+







    return(LIN16);
  }
}

void
SnackAudioGetRates(char *device, char *buf, int n)
{
  strncpy(buf, "8000 11025 16000 22050 32000 44100 48000", n);
  strncpy(buf, "8000 11025 16000 22050 32000 44100 48000 96000", n);
  buf[n-1] = '\0';
}

int
SnackAudioMaxNumberChannels(char *device)
{
  int i, devIndex = -1;
1373
1374
1375
1376
1377
1378
1379






1380
1381
1382
1383
1384
1385
1386
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392







+
+
+
+
+
+







	}
      }
    }
    */
  }
  return(2);
}

int
SnackAudioMinNumberChannels(char *device)
{
  return(1);
}

void
SnackMixerGetInputJackLabels(char *buf, int n)
{
  buf[0] = '\0';
}

Changes to snack/win/snack.dsp.

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
15
16
17
18
19
20
21

22
23
24
25
26
27
28







-







!MESSAGE 
!MESSAGE NMAKE /f "snack.mak" CFG="snack - Win32 Debug"
!MESSAGE 
!MESSAGE Possible choices for configuration are:
!MESSAGE 
!MESSAGE "snack - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "snack - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "snack - Win32 Tcl80" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE 

# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
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
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







-
+









-
+















-
+









-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







-







# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SNACK_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "C:\Program Files\Tcl\include" /I "../generic" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SNACK_EXPORTS" /D "WIN" /D "USE_TCL_STUBS" /D "USE_TK_STUBS" /D "TCL_81_API" /D "BUILD_snack" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "C:\Tcl\include" /I "../generic" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SNACK_EXPORTS" /D "WIN" /D "USE_TCL_STUBS" /D "USE_TK_STUBS" /D "TCL_81_API" /D "BUILD_snack" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 tclstub83.lib tkstub83.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /dll /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"C:\Program Files\Tcl\lib\snack2.0\libsnack.dll" /libpath:"C:\Program Files\Tcl\lib"
# ADD LINK32 tclstub83.lib tkstub83.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /dll /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"C:\Tcl\lib\snack2.1\libsnack.dll" /libpath:"C:\Tcl\lib"

!ELSEIF  "$(CFG)" == "snack - Win32 Debug"

# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SNACK_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "C:\Program Files\Tcl\include" /I "../generic" /D "_DEBUG" /D "WIN" /D "USE_TCL_STUBS" /D "USE_TK_STUBS" /D "TCL_81_API" /D "BUILD_snack" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SNACK_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "C:\Tcl\include" /I "../generic" /D "_DEBUG" /D "WIN" /D "USE_TCL_STUBS" /D "USE_TK_STUBS" /D "TCL_81_API" /D "BUILD_snack" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SNACK_EXPORTS" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib tclstub83.lib tkstub83.lib /nologo /dll /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"Debug/libsnack.dll" /pdbtype:sept /libpath:"C:\Program Files\Tcl\lib"
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib tclstub83.lib tkstub83.lib /nologo /dll /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"Debug/libsnack.dll" /pdbtype:sept /libpath:"C:\Tcl\lib"

!ELSEIF  "$(CFG)" == "snack - Win32 Tcl80"

# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "snack___Win32_Tcl80"
# PROP BASE Intermediate_Dir "snack___Win32_Tcl80"
# PROP BASE Ignore_Export_Lib 0
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "snack___Win32_Tcl80"
# PROP Intermediate_Dir "snack___Win32_Tcl80"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "C:\Program Files\Tcl\include" /I "../generic" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SNACK_EXPORTS" /D "WIN" /D "USE_TCL_STUBS" /D "USE_TK_STUBS" /D "TCL_81_API" /D "BUILD_snack" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "C:\Program Files\Tcl\include80" /I "../generic" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SNACK_EXPORTS" /D "WIN" /D "BUILD_snack" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 tclstub83.lib tkstub83.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /dll /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"C:\Program Files\Tcl\lib\snack2.0\libsnack.dll" /libpath:"C:\Program Files\Tcl\lib"
# ADD LINK32 tcl80.lib tk80.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /dll /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"C:\Program Files\Tcl\lib\snack2.0\libsnack.dll" /libpath:"C:\Program Files\Tcl\lib"

!ENDIF 

# Begin Target

# Name "snack - Win32 Release"
# Name "snack - Win32 Debug"
# Name "snack - Win32 Tcl80"
# Begin Group "Source Files"

# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File

SOURCE=..\generic\ffa.c
# End Source File
149
150
151
152
153
154
155
156

157
158
159
160
161
162
163
120
121
122
123
124
125
126

127
128
129
130
131
132
133
134







-
+







# End Source File
# Begin Source File

SOURCE=..\generic\jkFilter.c
# End Source File
# Begin Source File

SOURCE=..\generic\jkSynthesis.c
SOURCE=..\generic\jkFilterIIR.c
# End Source File
# Begin Source File

SOURCE=..\generic\jkFormatMP3.c
# End Source File
# Begin Source File

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
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







+
+
+
+














-
-
-
-
-
-
-
-
-
-
-







SOURCE=..\generic\jkSoundFile.c
# End Source File
# Begin Source File

SOURCE=..\generic\jkSoundProc.c
# End Source File
# Begin Source File

SOURCE=..\generic\jkSynthesis.c
# End Source File
# Begin Source File

SOURCE=..\generic\shape.c
# End Source File
# Begin Source File

SOURCE=..\generic\snack.c
# End Source File
# Begin Source File

SOURCE=.\snack.def
# End Source File
# Begin Source File

SOURCE=..\generic\snackStubInit.c

!IF  "$(CFG)" == "snack - Win32 Release"

!ELSEIF  "$(CFG)" == "snack - Win32 Debug"

!ELSEIF  "$(CFG)" == "snack - Win32 Tcl80"

# PROP Exclude_From_Build 1

!ENDIF 

# End Source File
# End Group
# Begin Group "Header Files"

# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File

Changes to snack/win/snackstub.dsp.

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
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







-
+







-
+














-
+







# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I "C:\Program Files\Tcl\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I "C:\Tcl\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"C:\Program Files\Tcl\lib\snack2.0\snackstub20.lib"
# ADD LIB32 /nologo /out:"C:\Tcl\lib\snack2.1\snackstub21.lib"

!ELSEIF  "$(CFG)" == "snackstub - Win32 Debug"

# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "C:\Program Files\Tcl\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "C:\Tcl\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo

Changes to snack/win/sound.dsp.

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
15
16
17
18
19
20
21

22
23
24
25
26
27
28







-







!MESSAGE 
!MESSAGE NMAKE /f "sound.mak" CFG="sound - Win32 Debug"
!MESSAGE 
!MESSAGE Possible choices for configuration are:
!MESSAGE 
!MESSAGE "sound - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "sound - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "sound - Win32 Tcl80" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE 

# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
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
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







-
+









-
+















-
+











-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-






-







# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOUND_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "C:\Program Files\Tcl\include" /I "../generic" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOUND_EXPORTS" /D "WIN" /D "USE_TCL_STUBS" /D "TCL_81_API" /D "BUILD_snack" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "C:\Tcl\include" /I "../generic" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOUND_EXPORTS" /D "WIN" /D "USE_TCL_STUBS" /D "TCL_81_API" /D "BUILD_snack" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib tclstub83.lib /nologo /dll /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"C:\Program Files\Tcl\lib\snack2.0\libsound.dll" /libpath:"C:\Program Files\Tcl\lib"
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib tclstub83.lib /nologo /dll /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"C:\Tcl\lib\snack2.1\libsound.dll" /libpath:"C:\Tcl\lib"

!ELSEIF  "$(CFG)" == "sound - Win32 Debug"

# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOUND_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "C:\Program Files\Tcl\include" /I "../generic" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOUND_EXPORTS" /D "WIN" /D "USE_TCL_STUBS" /D "TCL_81_API" /D "BUILD_snack" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "C:\Tcl\include" /I "../generic" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOUND_EXPORTS" /D "WIN" /D "USE_TCL_STUBS" /D "TCL_81_API" /D "BUILD_snack" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"Debug/libsound.dll" /pdbtype:sept

!ELSEIF  "$(CFG)" == "sound - Win32 Tcl80"

# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "sound___Win32_Tcl80"
# PROP BASE Intermediate_Dir "sound___Win32_Tcl80"
# PROP BASE Ignore_Export_Lib 0
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "sound___Win32_Tcl80"
# PROP Intermediate_Dir "sound___Win32_Tcl80"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "C:\Program Files\Tcl\include" /I "../generic" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOUND_EXPORTS" /D "WIN" /D "USE_TCL_STUBS" /D "TCL_81_API" /D "BUILD_snack" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "C:\Program Files\Tcl\include80" /I "../generic" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOUND_EXPORTS" /D "WIN" /D "BUILD_snack" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib tclstub83.lib /nologo /dll /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"C:\Program Files\Tcl\lib\snack2.0\libsound.dll" /libpath:"C:\Program Files\Tcl\lib"
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib tcl80.lib /nologo /dll /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"C:\Program Files\Tcl\lib\snack2.0\libsound.dll" /libpath:"C:\Program Files\Tcl\lib"

!ENDIF 

# Begin Target

# Name "sound - Win32 Release"
# Name "sound - Win32 Debug"
# Name "sound - Win32 Tcl80"
# Begin Group "Source Files"

# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File

SOURCE=..\generic\ffa.c
# End Source File
137
138
139
140
141
142
143
144

145
146
147
148
149
150
151
108
109
110
111
112
113
114

115
116
117
118
119
120
121
122







-
+







# End Source File
# Begin Source File

SOURCE=..\generic\jkFilter.c
# End Source File
# Begin Source File

SOURCE=..\generic\jkSynthesis.c
SOURCE=..\generic\jkFilterIIR.c
# End Source File
# Begin Source File

SOURCE=..\generic\jkFormatMP3.c
# End Source File
# Begin Source File

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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159











160
161
162
163
164
165
166







+
+
+
+






-
-
-
-
-
-
-
-
-
-
-







SOURCE=..\generic\jkSoundFile.c
# End Source File
# Begin Source File

SOURCE=..\generic\jkSoundProc.c
# End Source File
# Begin Source File

SOURCE=..\generic\jkSynthesis.c
# End Source File
# Begin Source File

SOURCE=..\generic\shape.c
# End Source File
# Begin Source File

SOURCE=..\generic\snackStubInit.c

!IF  "$(CFG)" == "sound - Win32 Release"

!ELSEIF  "$(CFG)" == "sound - Win32 Debug"

!ELSEIF  "$(CFG)" == "sound - Win32 Tcl80"

# PROP Exclude_From_Build 1

!ENDIF 

# End Source File
# Begin Source File

SOURCE=..\generic\sound.c
# End Source File
# Begin Source File