From: Martin Raspaud
Subject: Newbie : file handling
Date: 
Message-ID: <bq9lq6$oag$1@news-reader1.wanadoo.fr>
Hi,

I'm just starting to write a lisp program for music and I want to open a 
wav file and read its content and put it into an array.

Opening the file isn't much of a problem. The reading is more.
The 4 first bytes of the file contain "RIFF"
The next 4 bytes contain a 32bits integer giving the length of the file
the next 4 bytes contain "WAVE"
and so on.
My question is : how do I get the length of the file with lisp ? I tried 
"read-byte" with several type specifiers, but I can't get anything... 
each time I get 4 numbers corresponding to the 4 bytes, but I want 1 number.

I hope anyone has an answer...

Ps : I don't want to use a C program to do that.

Martin

From: Henrik Motakef
Subject: Re: Newbie : file handling
Date: 
Message-ID: <86k75jxrjs.fsf@pokey.internal.henrik-motakef.de>
Martin Raspaud <··············@wanadoo.fr> writes:

> Opening the file isn't much of a problem. The reading is more.
> The 4 first bytes of the file contain "RIFF"
> The next 4 bytes contain a 32bits integer giving the length of the file
> the next 4 bytes contain "WAVE"
> and so on.
> My question is : how do I get the length of the file with lisp?

FILE-LENGTH

> I tried "read-byte" with several type specifiers, but I can't get
> anything... each time I get 4 numbers corresponding to the 4 bytes,
> but I want 1 number.

If you use a stream with element-type (unsigned-byte 32), you should
be able to read 32-bit integers from the stream right away. If you
cannot do that, for example because you want to read 8-bit values
later, just combine your 4 8-bit numbers to one 32-bit one. You'll
want to look into the bit-fiddling functions like ASH, LDB and DPB.
From: Pascal Costanza
Subject: Re: Newbie : file handling
Date: 
Message-ID: <bqadjb$ooo$1@newsreader2.netcologne.de>
Martin Raspaud wrote:
> Hi,
> 
> I'm just starting to write a lisp program for music and I want to open a 
> wav file and read its content and put it into an array.
> 
> Opening the file isn't much of a problem. The reading is more.
> The 4 first bytes of the file contain "RIFF"
> The next 4 bytes contain a 32bits integer giving the length of the file
> the next 4 bytes contain "WAVE"
> and so on.
> My question is : how do I get the length of the file with lisp ? I tried 
> "read-byte" with several type specifiers, but I can't get anything... 
> each time I get 4 numbers corresponding to the 4 bytes, but I want 1 
> number.
> 
> I hope anyone has an answer...

I have written the following code to read Java class files. They use 
8-bit bytes to encode 16-bit, 32-bit and 64-bit values in big endian 
order. I have taken the approach to load a complete class file at once 
into a byte array and then decode the values from that array. The idea 
was to wait for profiling the actual behavior in order to see whether a 
more efficient approach is needed. However, I haven't yet gotten to that 
stage.

Here is the code. Note that some Common Lisp implementations might have 
serious limitations on the possible maximum size of arrays.

(defmacro with-open-class-file ((cf pathname) &body block)
   "similar to with-open-file"
   (with-unique-names (result)
     `(let* ((,cf (open-class-file ,pathname))
             (,result (progn ,@block)))
        (setf ,cf ())
        ,result)))

(defun open-class-file (class-file)
   "similar to open-file"
   (with-open-file (stream class-file :element-type '(unsigned-byte 8))
     (let ((cf (make-array (file-length stream)
                           :element-type '(unsigned-byte 8)
                           :fill-pointer t)))
       (read-sequence cf stream)
       (setf (fill-pointer cf) 0)
       cf)))

(defun read1 (cf)
   "read one byte from a class file"
   (let ((fp (fill-pointer cf)))
     (incf (fill-pointer cf))
     (aref cf fp)))

(defun bytes-to-int (arr &key (start 0) (end nil) (signed nil))
   "take a multibyte datum in big-endian order"
   (when (null end) (setq end (length arr)))
   (assert (< start end))
   (let ((len (- end start))
         (res (reduce (lambda (x y) (logior (ash x 8) y)) arr
                      :start start :end end :initial-value 0)))
     (if (and signed (> len 0))
       (let ((dec (expt 2 (ash len 3))))
         (if (>= res (ash dec -1))
           (- res (expt 2 (* len 8)))
           res))
       res)))

(defun readn (cf n &key (signed nil))
   "read n bytes from a class file"
   (let* ((start (fill-pointer cf))
          (end (setf (fill-pointer cf) (+ start n))))
     (bytes-to-int cf :start start :end end :signed signed)))


The code uses only standard stuff per ANSI Common Lisp. I guess other 
people probably have suggestions for improvement. (This code is already 
derived from various hints I have gotten from past c.l.l postings.)


Pascal

-- 
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: Thomas F. Burdick
Subject: Re: Newbie : file handling
Date: 
Message-ID: <xcvn0aezmkc.fsf@fallingrocks.OCF.Berkeley.EDU>
Martin Raspaud <··············@wanadoo.fr> writes:

> Hi,
> 
> I'm just starting to write a lisp program for music and I want to open a 
> wav file and read its content and put it into an array.
> 
> Opening the file isn't much of a problem. The reading is more.
> The 4 first bytes of the file contain "RIFF"
> The next 4 bytes contain a 32bits integer giving the length of the file
> the next 4 bytes contain "WAVE"
> and so on.
> My question is : how do I get the length of the file with lisp ? I tried 
> "read-byte" with several type specifiers, but I can't get anything... 
> each time I get 4 numbers corresponding to the 4 bytes, but I want 1 number.

If you open the file with an element type of (unxssnged-byte 32)
you'll get a raw stream of octets that you can assemble into whatever
Lisp object you want.  There are at least a couple utility libraries
out there to help with this, and sometimes your implementation has
other ways of doing this.  I use my own personal library for this
stuff.  Here's a small starting point:

  (defvar *endianness* :big)
  
  (declaim (inline read-byte*))
  (defun read-byte* (width stream &optional (eof-errorp t) eof-value)
    "Read an unsigned byte of WIDTH bits, from STREAM.
  WIDTH should be an even multiple of 8."
    (assert (zerop (mod width 8)))
    (ecase *endianness*
      (:big (loop with result = 0
                  for pos downfrom (- width 8) to 0 by 8
                  for byte = (read-byte stream eof-errorp eof-value)
                  do (setf (ldb (byte 8 pos) result) byte)
                  finally (return result)))))
  
To extend it to read in little-endian order (which I'm guessing WAV
files use), just make pos go up, not down.  Yow, apparently I haven't
needed to read from a little-endian byte stream in a long, long time :)

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Tiscali News
Subject: Re: Newbie : file handling
Date: 
Message-ID: <bqaodl$49b$1@ctb-nnrp2.saix.net>
"Martin Raspaud" <··············@wanadoo.fr> wrote in message
·················@news-reader1.wanadoo.fr...
> Hi,
>
> I'm just starting to write a lisp program for music and I want to open a
> wav file and read its content and put it into an array.
>
> Opening the file isn't much of a problem. The reading is more.
> The 4 first bytes of the file contain "RIFF"
> The next 4 bytes contain a 32bits integer giving the length of the file
> the next 4 bytes contain "WAVE"
> and so on.
> My question is : how do I get the length of the file with lisp ?

file-length returns the length of stream, or nil if the length cannot be
determined.

For a binary file, the length is measured in units of the element type of
the stream.


Examples:



 (with-open-file (s "decimal-digits.text"
                    :direction :output :if-exists :error)
   (princ "0123456789" s)
   (truename s))
=>  #P"A:>Joe>decimal-digits.text.1"
 (with-open-file (s "decimal-digits.text")
   (file-length s))
=>  10
element type  = stream element type n. (of a stream) the type of data for
which the stream is specialized.

>I tried
> "read-byte" with several type specifiers, but I can't get anything...
> each time I get 4 numbers corresponding to the 4 bytes, but I want 1
number.
>
> I hope anyone has an answer...
>
> Ps : I don't want to use a C program to do that.
>
> Martin
>
From: Martin Raspaud
Subject: Re: Newbie : file handling
Date: 
Message-ID: <bqd301$t0m$1@news-reader2.wanadoo.fr>
Thanx all for your answers, I got something working good for me.

It's a lisp library I found here (binary-types).

Martin