1 /* libSoX Sound Blaster VOC handler sources.
2 * Copyright 1991 Lance Norskog And Sundry Contributors
4 * This source code is freely redistributable and may be used for
5 * any purpose. This copyright notice must be maintained.
6 * Lance Norskog And Sundry Contributors are not responsible for
7 * the consequences of using this software.
10 * Copyright 1993 T. Allen Grider - for changes to support block type 9
11 * and word sized samples. Same caveats and disclaimer as above.
14 * by Chris Bagwell (cbagwell@sprynet.com)
15 * Added support for block type 8 (extended) which allows for 8-bit stereo
16 * files. Added support for saving stereo files and 16-bit files.
17 * Added VOC format info from audio format FAQ so I don't have to keep
18 * looking around for it.
21 * For sox-12-17 by Annonymous (see notes ANN)
22 * Added comments and notes for each procedure.
23 * Fixed so this now works with pipes, input does not have to
24 * be seekable anymore (in startread() )
25 * Added support for uLAW and aLaw (aLaw not tested).
26 * Fixed support of multi-part VOC files, and files with
27 * block 9 but no audio in the block....
28 * The following need to be tested: 16-bit, 2 channel, and aLaw.
31 * For sox-12-17-3 by Annonymous (see notes ANN)
32 * Patch for sox-12-17 merged with sox-12-17-3-pre3 code.
36 /*------------------------------------------------------------------------
37 The following is taken from the Audio File Formats FAQ dated 2-Jan-1995
38 and submitted by Guido van Rossum <guido@cwi.nl>.
39 --------------------------------------------------------------------------
40 Creative Voice (VOC) file format
41 --------------------------------
45 (byte numbers are hex!)
48 Series of DATA BLOCKS (bytes 1A+) [Must end w/ Terminator Block]
50 - ---------------------------------------------------------------
55 ------ ------------------------------------------
56 00-12 "Creative Voice File"
57 13 1A (eof to abort printing of file)
58 14-15 Offset of first datablock in .voc file (std 1A 00
60 16-17 Version number (minor,major) (VOC-HDR puts 0A 01)
61 18-19 2's Comp of Ver. # + 1234h (VOC-HDR puts 29 11)
63 - ---------------------------------------------------------------
68 Data Block: TYPE(1-byte), SIZE(3-bytes), INFO(0+ bytes)
69 NOTE: Terminator Block is an exception -- it has only the TYPE byte.
71 TYPE Description Size (3-byte int) Info
72 ---- ----------- ----------------- -----------------------
73 00 Terminator (NONE) (NONE)
74 01 Sound data 2+length of data *
75 02 Sound continue length of data Voice Data
77 04 Marker 2 Marker# (2 bytes)
78 05 ASCII length of string null terminated string
79 06 Repeat 2 Count# (2 bytes)
80 07 End repeat 0 (NONE)
82 09 New Header 16 see below
85 *Sound Info Format: **Silence Info Format:
86 --------------------- ----------------------------
87 00 Sample Rate 00-01 Length of silence - 1
88 01 Compression Type 02 Sample Rate
91 ***Extended Info Format:
93 00-01 Time Constant: Mono: 65536 - (256000000/sample_rate)
94 Stereo: 65536 - (25600000/(2*sample_rate))
100 Marker# -- Driver keeps the most recent marker in a status byte
101 Count# -- Number of repetitions + 1
102 Count# may be 1 to FFFE for 0 - FFFD repetitions
103 or FFFF for endless repetitions
104 Sample Rate -- SR byte = 256-(1000000/sample_rate)
105 Length of silence -- in units of sampling cycle
106 Compression Type -- of voice data
111 Multi DAC = 3+(# of channels) [interesting--
112 this isn't in the developer's manual]
114 Detailed description of new data blocks (VOC files version 1.20 and above):
116 (Source is fax from Barry Boone at Creative Labs, 405/742-6622)
118 BLOCK 8 - digitized sound attribute extension, must preceed block 1.
119 Used to define stereo, 8 bit audio
120 BYTE bBlockID; // = 8
121 BYTE nBlockLen[3]; // 3 byte length
122 WORD wTimeConstant; // time constant = same as block 1
123 BYTE bPackMethod; // same as in block 1
124 BYTE bVoiceMode; // 0-mono, 1-stereo
126 Data is stored left, right
128 BLOCK 9 - data block that supersedes blocks 1 and 8.
129 Used for stereo, 16 bit (and uLaw, aLaw).
131 BYTE bBlockID; // = 9
132 BYTE nBlockLen[3]; // length 12 plus length of sound
133 DWORD dwSamplesPerSec; // samples per second, not time const.
134 BYTE bBitsPerSample; // e.g., 8 or 16
135 BYTE bChannels; // 1 for mono, 2 for stereo
136 WORD wFormat; // see below
137 BYTE reserved[4]; // pad to make block w/o data
138 // have a size of 16 bytes
140 Valid values of wFormat are:
142 0x0000 8-bit unsigned PCM
143 0x0001 Creative 8-bit to 4-bit ADPCM
144 0x0002 Creative 8-bit to 3-bit ADPCM
145 0x0003 Creative 8-bit to 2-bit ADPCM
146 0x0004 16-bit signed PCM
149 0x02000 Creative 16-bit to 4-bit ADPCM
151 Data is stored left, right
153 ANN: Multi-byte quantities are in Intel byte order (Little Endian).
155 ------------------------------------------------------------------------*/
163 /* Private data for VOC file */
165 long block_remaining
; /* bytes remaining in current block */
166 long rate
; /* rate code (byte) of this chunk */
167 int silent
; /* sound or silence? */
168 long srate
; /* rate code (byte) of silence */
169 size_t blockseek
; /* start of current output block */
170 long samples
; /* number of samples output */
171 int format
; /* VOC audio format */
172 int size
; /* word length of data */
173 int channels
; /* number of sound channels */
174 long total_size
; /* total size of all audio in file */
175 int extended
; /* Has an extended block been read? */
182 #define VOC_SILENCE 3
186 #define VOC_LOOPEND 7
187 #define VOC_EXTENDED 8
188 #define VOC_DATA_16 9
190 /* ANN: Format encoding types */
191 #define VOC_FMT_LIN8U 0 /* 8 bit unsigned linear PCM */
192 #define VOC_FMT_CRLADPCM4 1 /* Creative 8-bit to 4-bit ADPCM */
193 #define VOC_FMT_CRLADPCM3 2 /* Creative 8-bit to 3-bit ADPCM */
194 #define VOC_FMT_CRLADPCM2 3 /* Creative 8-bit to 2-bit ADPCM */
195 #define VOC_FMT_LIN16 4 /* 16-bit signed PCM */
196 #define VOC_FMT_ALAW 6 /* CCITT a-Law 8-bit PCM */
197 #define VOC_FMT_MU255 7 /* CCITT u-Law 8-bit PCM */
198 #define VOC_FMT_CRLADPCM4A 0x200 /* Creative 16-bit to 4-bit ADPCM */
200 /* Prototypes for internal functions */
201 static int getblock(sox_format_t
*);
202 static void blockstart(sox_format_t
*);
204 /* Conversion macros (from raw.c) */
205 #define SOX_ALAW_BYTE_TO_SAMPLE(d) ((sox_sample_t)(sox_alaw2linear16(d)) << 16)
206 #define SOX_ULAW_BYTE_TO_SAMPLE(d) ((sox_sample_t)(sox_ulaw2linear16(d)) << 16)
208 /* public VOC functions for SOX */
210 /*-----------------------------------------------------------------
211 * startread() -- start reading a VOC file
212 *-----------------------------------------------------------------*/
213 static int startread(sox_format_t
* ft
)
216 priv_t
* v
= (priv_t
*) ft
->priv
;
217 unsigned short sbseek
;
219 int ii
; /* for getting rid of lseek */
222 if (lsx_readbuf(ft
, header
, (size_t)20) != 20) {
223 lsx_fail_errno(ft
, SOX_EHDR
, "unexpected EOF in VOC header");
226 if (strncmp(header
, "Creative Voice File\032", (size_t)19)) {
227 lsx_fail_errno(ft
, SOX_EHDR
, "VOC file header incorrect");
231 /* read the offset to data, from start of file */
232 /* after this read we have read 20 bytes of header + 2 */
233 lsx_readw(ft
, &sbseek
);
235 /* ANN: read to skip the header, instead of lseek */
236 /* this should allow use with pipes.... */
237 for (ii
= 22; ii
< sbseek
; ii
++)
243 v
->block_remaining
= 0;
244 v
->total_size
= 0; /* ANN added */
247 /* read until we get the format information.... */
252 /* get rate of data */
254 lsx_fail_errno(ft
, SOX_EOF
, "Input .voc file had no sound!");
258 /* setup word length of data */
260 /* ANN: Check VOC format and map to the proper libSoX format value */
262 case VOC_FMT_LIN8U
: /* 0 8 bit unsigned linear PCM */
263 ft
->encoding
.encoding
= SOX_ENCODING_UNSIGNED
;
266 case VOC_FMT_CRLADPCM4
: /* 1 Creative 8-bit to 4-bit ADPCM */
267 ft
->encoding
.encoding
= SOX_ENCODING_CL_ADPCM
;
270 case VOC_FMT_CRLADPCM3
: /* 2 Creative 8-bit to 3-bit ADPCM */
271 ft
->encoding
.encoding
= SOX_ENCODING_CL_ADPCM
;
274 case VOC_FMT_CRLADPCM2
: /* 3 Creative 8-bit to 2-bit ADPCM */
275 ft
->encoding
.encoding
= SOX_ENCODING_CL_ADPCM
;
278 case VOC_FMT_LIN16
: /* 4 16-bit signed PCM */
279 ft
->encoding
.encoding
= SOX_ENCODING_SIGN2
;
282 case VOC_FMT_ALAW
: /* 6 CCITT a-Law 8-bit PCM */
283 ft
->encoding
.encoding
= SOX_ENCODING_ALAW
;
286 case VOC_FMT_MU255
: /* 7 CCITT u-Law 8-bit PCM */
287 ft
->encoding
.encoding
= SOX_ENCODING_ULAW
;
290 case VOC_FMT_CRLADPCM4A
: /*0x200 Creative 16-bit to 4-bit ADPCM */
291 ft
->encoding
.encoding
= SOX_ENCODING_CL_ADPCM16
;
295 lsx_fail("Unknown VOC format %d", v
->format
);
298 ft
->encoding
.bits_per_sample
= v
->size
;
300 /* setup number of channels */
301 if (ft
->signal
.channels
== 0)
302 ft
->signal
.channels
= v
->channels
;
304 return (SOX_SUCCESS
);
307 /*-----------------------------------------------------------------
308 * read() -- read data from a VOC file
309 * ANN: Major changes here to support multi-part files and files
310 * that do not have audio in block 9's.
311 *-----------------------------------------------------------------*/
312 static size_t read_samples(sox_format_t
* ft
, sox_sample_t
* buf
,
315 priv_t
* v
= (priv_t
*) ft
->priv
;
321 if (v
->block_remaining
== 0) { /* handle getting another cont. buffer */
327 if (v
->block_remaining
== 0) /* if no more data, return 0, i.e., done */
331 for (; v
->block_remaining
&& (done
< len
); v
->block_remaining
--, done
++)
332 *buf
++ = 0; /* Fill in silence */
333 } else { /* not silence; read len samples of audio from the file */
334 size_t per
= max(1, 9 / v
->size
);
336 for (; (done
+ per
<= len
); done
+= per
) {
337 if (v
->block_remaining
== 0) { /* IF no more in this block, get another */
338 while (v
->block_remaining
== 0) { /* until have either EOF or a block with data */
343 if (rc
) /* IF EOF, break out, no more data, next will return 0 */
347 /* Read the data in the file */
349 if (!v
->adpcm
.setup
.sign
) {
351 if (lsx_readb(ft
, &uc
) == SOX_EOF
) {
352 lsx_warn("VOC input: short file");
353 v
->block_remaining
= 0;
356 *buf
= SOX_UNSIGNED_8BIT_TO_SAMPLE(uc
,);
357 lsx_adpcm_init(&v
->adpcm
, 6 - v
->size
, SOX_SAMPLE_TO_SIGNED_16BIT(*buf
, ft
->clips
));
359 --v
->block_remaining
;
362 if (lsx_readb(ft
, &uc
) == SOX_EOF
) {
363 lsx_warn("VOC input: short file");
364 v
->block_remaining
= 0;
369 if (v
->format
== VOC_FMT_CRLADPCM2
) {
373 SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u
>> 6, &v
->adpcm
),);
375 SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u
>> 4, &v
->adpcm
),);
377 SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u
>> 2, &v
->adpcm
),);
379 SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u
, &v
->adpcm
),);
383 if (v
->format
== VOC_FMT_CRLADPCM3
) {
387 SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u
>> 5, &v
->adpcm
),);
389 SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u
>> 2, &v
->adpcm
),);
390 *buf
++ = /* A bit from nowhere! */
391 SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u
<< 1, &v
->adpcm
),);
395 if (v
->format
== VOC_FMT_CRLADPCM4
) {
399 SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u
>> 4, &v
->adpcm
),);
401 SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u
, &v
->adpcm
),);
408 if (lsx_readb(ft
, &uc
) == SOX_EOF
) {
409 lsx_warn("VOC input: short file");
410 v
->block_remaining
= 0;
413 if (v
->format
== VOC_FMT_MU255
) {
414 *buf
++ = SOX_ULAW_BYTE_TO_SAMPLE(uc
);
415 } else if (v
->format
== VOC_FMT_ALAW
) {
416 *buf
++ = SOX_ALAW_BYTE_TO_SAMPLE(uc
);
418 *buf
++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(uc
,);
424 lsx_warn("VOC input: short file");
425 v
->block_remaining
= 0;
428 *buf
++ = SOX_SIGNED_16BIT_TO_SAMPLE(sw
,);
429 v
->block_remaining
--; /* Processed 2 bytes so update */
432 /* decrement count of processed bytes */
433 v
->block_remaining
--;
436 v
->total_size
+= done
;
441 /* When saving samples in VOC format the following outline is followed:
442 * If an 8-bit mono sample then use a VOC_DATA header.
443 * If an 8-bit stereo sample then use a VOC_EXTENDED header followed
444 * by a VOC_DATA header.
445 * If a 16-bit sample (either stereo or mono) then save with a
446 * VOC_DATA_16 header.
448 * ANN: Not supported: uLaw and aLaw output VOC files....
450 * This approach will cause the output to be an its most basic format
451 * which will work with the oldest software (eg. an 8-bit mono sample
452 * will be able to be played with a really old SB VOC player.)
454 static int startwrite(sox_format_t
* ft
)
456 priv_t
* v
= (priv_t
*) ft
->priv
;
459 lsx_fail_errno(ft
, SOX_EOF
,
460 "Output .voc file must be a file, not a pipe");
466 /* File format name and a ^Z (aborts printing under DOS) */
467 lsx_writes(ft
, "Creative Voice File\032");
468 lsx_writew(ft
, 26); /* size of header */
469 lsx_writew(ft
, 0x10a); /* major/minor version number */
470 lsx_writew(ft
, 0x1129); /* checksum of version number */
472 return (SOX_SUCCESS
);
475 /*-----------------------------------------------------------------
476 * write() -- write a VOC file
477 *-----------------------------------------------------------------*/
478 static size_t write_samples(sox_format_t
* ft
, const sox_sample_t
* buf
,
481 priv_t
* v
= (priv_t
*) ft
->priv
;
486 if (len
&& v
->samples
== 0) {
487 /* No silence packing yet. */
494 if (ft
->encoding
.bits_per_sample
== 8) {
495 uc
= SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf
++, ft
->clips
);
498 sw
= (int) SOX_SAMPLE_TO_SIGNED_16BIT(*buf
++, ft
->clips
);
506 /*-----------------------------------------------------------------
507 * blockstop() -- stop an output block
508 * End the current data or silence block.
509 *-----------------------------------------------------------------*/
510 static void blockstop(sox_format_t
* ft
)
512 priv_t
* v
= (priv_t
*) ft
->priv
;
515 lsx_writeb(ft
, 0); /* End of file block code */
516 lsx_seeki(ft
, (off_t
) v
->blockseek
, 0); /* seek back to block length */
517 lsx_seeki(ft
, (off_t
)1, 1); /* seek forward one */
519 lsx_writesw(ft
, (signed)v
->samples
);
521 if (ft
->encoding
.bits_per_sample
== 8) {
522 if (ft
->signal
.channels
> 1) {
523 lsx_seeki(ft
, (off_t
)8, 1); /* forward 7 + 1 for new block header */
526 v
->samples
+= 2; /* adjustment: SBDK pp. 3-5 */
527 datum
= (v
->samples
* (ft
->encoding
.bits_per_sample
>> 3)) & 0xff;
528 lsx_writesb(ft
, datum
); /* low byte of length */
529 datum
= ((v
->samples
* (ft
->encoding
.bits_per_sample
>> 3)) >> 8) & 0xff;
530 lsx_writesb(ft
, datum
); /* middle byte of length */
531 datum
= ((v
->samples
* (ft
->encoding
.bits_per_sample
>> 3)) >> 16) & 0xff;
532 lsx_writesb(ft
, datum
); /* high byte of length */
536 /*-----------------------------------------------------------------
537 * stopwrite() -- stop writing a VOC file
538 *-----------------------------------------------------------------*/
539 static int stopwrite(sox_format_t
* ft
)
542 return (SOX_SUCCESS
);
545 /*-----------------------------------------------------------------
546 * Voc-file handlers (static, private to this module)
547 *-----------------------------------------------------------------*/
549 /*-----------------------------------------------------------------
550 * getblock() -- Read next block header, save info,
551 * leave position at start of dat
552 *-----------------------------------------------------------------*/
553 static int getblock(sox_format_t
* ft
)
555 priv_t
* v
= (priv_t
*) ft
->priv
;
556 unsigned char uc
, block
;
559 uint16_t new_rate_16
;
560 uint32_t new_rate_32
;
563 /* DO while we have no audio to read */
564 while (v
->block_remaining
== 0) {
568 if (lsx_readb(ft
, &block
) == SOX_EOF
)
571 if (block
== VOC_TERM
)
577 lsx_read3(ft
, &sblen
);
579 /* Based on VOC block type, process the block */
580 /* audio may be in one or multiple blocks */
584 /* When DATA block preceeded by an EXTENDED */
585 /* block, the DATA blocks rate value is invalid */
588 lsx_fail_errno(ft
, SOX_EFMT
, "Sample rate is zero?");
591 if ((v
->rate
!= -1) && (uc
!= v
->rate
)) {
592 lsx_fail_errno(ft
, SOX_EFMT
,
593 "sample rate codes differ: %ld != %d", v
->rate
,
598 ft
->signal
.rate
= 1000000.0 / (256 - v
->rate
);
599 if (v
->channels
!= -1 && v
->channels
!= 1) {
600 lsx_fail_errno(ft
, SOX_EFMT
, "channel count changed");
606 if (v
->format
!= -1 && uc
!= v
->format
) {
607 lsx_fail_errno(ft
, SOX_EFMT
, "format changed");
612 v
->block_remaining
= sblen
- 2;
613 return (SOX_SUCCESS
);
615 lsx_readdw(ft
, &new_rate_32
);
616 if (new_rate_32
== 0) {
617 lsx_fail_errno(ft
, SOX_EFMT
, "Sample rate is zero?");
620 if ((v
->rate
!= -1) && ((long) new_rate_32
!= v
->rate
)) {
621 lsx_fail_errno(ft
, SOX_EFMT
, "sample rate codes differ: %ld != %d",
622 v
->rate
, new_rate_32
);
625 v
->rate
= new_rate_32
;
626 ft
->signal
.rate
= new_rate_32
;
630 if (v
->channels
!= -1 && uc
!= v
->channels
) {
631 lsx_fail_errno(ft
, SOX_EFMT
, "channel count changed");
635 lsx_readw(ft
, &u16
); /* ANN: added format */
636 if (v
->format
!= -1 && u16
!= v
->format
) {
637 lsx_fail_errno(ft
, SOX_EFMT
, "format changed");
641 lsx_skipbytes(ft
, (size_t) 4);
642 v
->block_remaining
= sblen
- 12;
643 return (SOX_SUCCESS
);
645 v
->block_remaining
= sblen
;
646 return (SOX_SUCCESS
);
649 unsigned short period
;
651 lsx_readw(ft
, &period
);
654 lsx_fail_errno(ft
, SOX_EFMT
, "Silence sample rate is zero");
658 * Some silence-packed files have gratuitously
659 * different sample rate codes in silence.
662 if ((v
->rate
!= -1) && (uc
!= v
->rate
))
663 period
= (period
* (256. - uc
)) / (256 - v
->rate
) + .5;
666 v
->block_remaining
= period
;
668 return (SOX_SUCCESS
);
673 /* Falling! Falling! */
677 int8_t c
/*, line_buf[80];
680 lsx_warn("VOC TEXT");
683 /* FIXME: this needs to be tested but I couldn't
684 * find a voc file with a VOC_TEXT chunk :(
685 if (c != '\0' && c != '\r')
687 if (len && (c == '\0' || c == '\r' ||
688 i == 0 || len == sizeof(line_buf) - 1))
690 lsx_report("%s", line_buf);
691 line_buf[len] = '\0';
697 continue; /* get next block */
700 lsx_debug("skipping repeat loop");
701 lsx_skipbytes(ft
, (size_t) sblen
);
704 /* An Extended block is followed by a data block */
705 /* Set this byte so we know to use the rate */
706 /* value from the extended block and not the */
709 lsx_readw(ft
, &new_rate_16
);
710 if (new_rate_16
== 0) {
711 lsx_fail_errno(ft
, SOX_EFMT
, "Sample rate is zero?");
714 if ((v
->rate
!= -1) && (new_rate_16
!= v
->rate
)) {
715 lsx_fail_errno(ft
, SOX_EFMT
, "sample rate codes differ: %ld != %d",
716 v
->rate
, new_rate_16
);
719 v
->rate
= new_rate_16
;
720 lsx_readb(ft
, &uc
); /* bits_per_sample */
722 if (v
->channels
!= -1 && uc
!= v
->channels
) {
723 lsx_fail_errno(ft
, SOX_EFMT
, "channel count changed");
727 ft
->signal
.channels
= uc
? 2 : 1; /* Stereo */
728 /* Needed number of channels before finishing
729 * compute for rate */
730 ft
->signal
.rate
= (256e6
/ (65536 - v
->rate
)) / ft
->signal
.channels
;
731 /* An extended block must be followed by a data */
732 /* block to be valid so loop back to top so it */
736 lsx_debug("skipping unknown block code %d", block
);
737 lsx_skipbytes(ft
, (size_t) sblen
);
743 /*-----------------------------------------------------------------
744 * vlockstart() -- start an output block
745 *-----------------------------------------------------------------*/
746 static void blockstart(sox_format_t
* ft
)
748 priv_t
* v
= (priv_t
*) ft
->priv
;
750 v
->blockseek
= lsx_tell(ft
);
752 lsx_writeb(ft
, VOC_SILENCE
); /* Silence block code */
753 lsx_writeb(ft
, 0); /* Period length */
754 lsx_writeb(ft
, 0); /* Period length */
755 lsx_writesb(ft
, (signed)v
->rate
); /* Rate code */
757 if (ft
->encoding
.bits_per_sample
== 8) {
758 /* 8-bit sample section. By always setting the correct */
759 /* rate value in the DATA block (even when its preceeded */
760 /* by an EXTENDED block) old software can still play stereo */
761 /* files in mono by just skipping over the EXTENDED block. */
762 /* Prehaps the rate should be doubled though to make up for */
763 /* double amount of samples for a given time???? */
764 if (ft
->signal
.channels
> 1) {
765 lsx_writeb(ft
, VOC_EXTENDED
); /* Voice Extended block code */
766 lsx_writeb(ft
, 4); /* block length = 4 */
767 lsx_writeb(ft
, 0); /* block length = 4 */
768 lsx_writeb(ft
, 0); /* block length = 4 */
769 v
->rate
= 65536 - (256000000.0 / (2 * ft
->signal
.rate
)) + .5;
770 lsx_writesw(ft
, (signed) v
->rate
); /* Rate code */
771 lsx_writeb(ft
, 0); /* File is not packed */
772 lsx_writeb(ft
, 1); /* samples are in stereo */
774 lsx_writeb(ft
, VOC_DATA
); /* Voice Data block code */
775 lsx_writeb(ft
, 0); /* block length (for now) */
776 lsx_writeb(ft
, 0); /* block length (for now) */
777 lsx_writeb(ft
, 0); /* block length (for now) */
778 v
->rate
= 256 - (1000000.0 / ft
->signal
.rate
) + .5;
779 lsx_writesb(ft
, (signed) v
->rate
); /* Rate code */
780 lsx_writeb(ft
, 0); /* 8-bit raw data */
782 lsx_writeb(ft
, VOC_DATA_16
); /* Voice Data block code */
783 lsx_writeb(ft
, 0); /* block length (for now) */
784 lsx_writeb(ft
, 0); /* block length (for now) */
785 lsx_writeb(ft
, 0); /* block length (for now) */
786 v
->rate
= ft
->signal
.rate
+ .5;
787 lsx_writedw(ft
, (unsigned) v
->rate
); /* Rate code */
788 lsx_writeb(ft
, 16); /* Sample Size */
789 lsx_writeb(ft
, ft
->signal
.channels
); /* Sample Size */
790 lsx_writew(ft
, 0x0004); /* Encoding */
791 lsx_writeb(ft
, 0); /* Unused */
792 lsx_writeb(ft
, 0); /* Unused */
793 lsx_writeb(ft
, 0); /* Unused */
794 lsx_writeb(ft
, 0); /* Unused */
799 LSX_FORMAT_HANDLER(voc
)
801 static char const *const names
[] = { "voc", NULL
};
802 static unsigned const write_encodings
[] = {
803 SOX_ENCODING_SIGN2
, 16, 0,
804 SOX_ENCODING_UNSIGNED
, 8, 0,
807 static sox_format_handler_t
const handler
= {SOX_LIB_VERSION_CODE
,
808 "Creative Technology Sound Blaster format",
809 names
, SOX_FILE_LIT_END
| SOX_FILE_MONO
| SOX_FILE_STEREO
,
810 startread
, read_samples
, NULL
,
811 startwrite
, write_samples
, stopwrite
,
812 NULL
, write_encodings
, NULL
, sizeof(priv_t
)