Peter Siebel - Practical Common Lisp

Здесь есть возможность читать онлайн «Peter Siebel - Practical Common Lisp» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Год выпуска: 2005, ISBN: 2005, Издательство: Apress, Жанр: Программирование, на английском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.

Practical Common Lisp: краткое содержание, описание и аннотация

Предлагаем к чтению аннотацию, описание, краткое содержание или предисловие (зависит от того, что написал сам автор книги «Practical Common Lisp»). Если вы не нашли необходимую информацию о книге — напишите в комментариях, мы постараемся отыскать её.

Practical Common Lisp — читать онлайн бесплатно полную книгу (весь текст) целиком

Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «Practical Common Lisp», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

(loop

for char across text

for i from 1

do (setf (aref buffer i) (char-code char)))

buffer))

Depending on how your particular Lisp implementation handles its streams, and also how many MP3 clients you want to serve at once, the simple version of play-currentmay or may not be efficient enough.

The potential problem with the simple implementation is that you have to call READ-BYTE and WRITE-BYTE for every byte you transfer. It's possible that each call may result in a relatively expensive system call to read or write one byte. And even if Lisp implements its own streams with internal buffering so not every call to READ-BYTE or WRITE-BYTE results in a system call, function calls still aren't free. In particular, in implementations that provide user-extensible streams using so-called Gray Streams, READ-BYTE and WRITE-BYTE may result in a generic function call under the covers to dispatch on the class of the stream argument. While generic function dispatch is normally speedy enough that you don't have to worry about it, it's a bit more expensive than a nongeneric function call and thus not something you necessarily want to do several million times in a few minutes if you can avoid it.

A more efficient, if slightly more complex, way to implement play-currentis to read and write multiple bytes at a time using the functions READ-SEQUENCE and WRITE-SEQUENCE . This also gives you a chance to match your file reads with the natural block size of the file system, which will likely give you the best disk throughput. Of course, no matter what buffer size you use, keeping track of when to send the metadata becomes a bit more complicated. A more efficient version of play-currentthat uses READ-SEQUENCE and WRITE-SEQUENCE might look like this:

(defun play-current (out song-source next-metadata metadata-interval)

(let ((song (current-song song-source)))

(when song

(let ((metadata (make-icy-metadata (title song)))

(buffer (make-array size :element-type '(unsigned-byte 8))))

(with-open-file (mp3 (file song))

(labels ((write-buffer (start end)

(if metadata-interval

(write-buffer-with-metadata start end)

(write-sequence buffer out :start start :end end)))

(write-buffer-with-metadata (start end)

(cond

((> next-metadata (- end start))

(write-sequence buffer out :start start :end end)

(decf next-metadata (- end start)))

(t

(let ((middle (+ start next-metadata)))

(write-sequence buffer out :start start :end middle)

(write-sequence metadata out)

(setf next-metadata metadata-interval)

(write-buffer-with-metadata middle end))))))

(multiple-value-bind (skip-blocks skip-bytes)

(floor (id3-size song) (length buffer))

(unless (file-position mp3 (* skip-blocks (length buffer)))

(error "Couldn't skip over ~d ~d byte blocks."

skip-blocks (length buffer)))

(loop for end = (read-sequence buffer mp3)

for start = skip-bytes then 0

do (write-buffer start end)

while (and (= end (length buffer))

(still-current-p song song-source)))

(maybe-move-to-next-song song song-source)))))

next-metadata)))

Now you're ready to put all the pieces together. In the next chapter you'll write a Web interface to the Shoutcast server developed in this chapter, using the MP3 database from Chapter 27 as the source of songs.

29. Practical: An MP3 Browser

The final step in building the MP3 streaming application is to provide a Web interface that allows a user to find the songs they want to listen to and add them to a playlist that the Shoutcast server will draw upon when the user's MP3 client requests the stream URL. For this component of the application, you'll pull together several bits of code from the previous few chapters: the MP3 database, the define-url-functionmacro from Chapter 26, and, of course, the Shoutcast server itself.

Playlists

The basic idea behind the interface will be that each MP3 client that connects to the Shoutcast server gets its own playlist , which serves as the source of songs for the Shoutcast server. A playlist will also provide facilities beyond those needed by the Shoutcast server: through the Web interface the user will be able to add songs to the playlist, delete songs already in the playlist, and reorder the playlist by sorting and shuffling.

You can define a class to represent playlists like this:

(defclass playlist ()

((id :accessor id :initarg :id)

(songs-table :accessor songs-table :initform (make-playlist-table))

(current-song :accessor current-song :initform *empty-playlist-song*)

(current-idx :accessor current-idx :initform 0)

(ordering :accessor ordering :initform :album)

(shuffle :accessor shuffle :initform :none)

(repeat :accessor repeat :initform :none)

(user-agent :accessor user-agent :initform "Unknown")

(lock :reader lock :initform (make-process-lock))))

The idof a playlist is the key you extract from the request object passed to find-song-sourcewhen looking up a playlist. You don't actually need to store it in the playlistobject, but it makes debugging a bit easier if you can find out from an arbitrary playlist object what its idis.

The heart of the playlist is the songs-tableslot, which will hold a tableobject. The schema for this table will be the same as for the main MP3 database. The function make-playlist-table, which you use to initialize songs-table, is simply this:

(defun make-playlist-table ()

(make-instance 'table :schema *mp3-schema*))

The Package

You can define the package for the code in this chapter with the following DEFPACKAGE :

(defpackage :com.gigamonkeys.mp3-browser

(:use :common-lisp

:net.aserve

:com.gigamonkeys.html

:com.gigamonkeys.shoutcast

:com.gigamonkeys.url-function

:com.gigamonkeys.mp3-database

:com.gigamonkeys.id3v2)

(:import-from :acl-socket

:ipaddr-to-dotted

:remote-host)

(:import-from :multiprocessing

:make-process-lock

:with-process-lock)

(:export :start-mp3-browser))

Because this is a high-level application, it uses a lot of lower-level packages. It also imports three symbols from the ACL-SOCKETpackage and two more from MULTIPROCESSINGsince it just needs those five and not the other 139 symbols those two packages export.

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Похожие книги на «Practical Common Lisp»

Представляем Вашему вниманию похожие книги на «Practical Common Lisp» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.


Отзывы о книге «Practical Common Lisp»

Обсуждение, отзывы о книге «Practical Common Lisp» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.

x