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», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

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

Интервал:

Закладка:

Сделать

;; iTunes, despite claiming to speak HTTP/1.1, doesn't understand

;; chunked Transfer-encoding. Grrr. So we just turn it off.

(turn-off-chunked-transfer-encoding request))

(defun turn-off-chunked-transfer-encoding (request)

(setf (request-reply-strategy request)

(remove :chunked (request-reply-strategy request))))

Within the with-http-bodyof shoutcast, you actually stream the MP3 data. The function play-songstakes the stream to which it should write the data, the song source, and the metadata interval it should use or NIL if the client doesn't want metadata. The stream is the socket obtained from the request object, the song source is obtained by calling find-song-source, and the metadata interval comes from the global variable *metadata-interval*. The type of song source is controlled by the variable *song-source-type*, which for now you can set to singletonin order to use the simple-song-queueyou implemented previously.

(defparameter *metadata-interval* (expt 2 12))

(defparameter *song-source-type* 'singleton)

The function play-songsitself doesn't do much—it loops calling the function play-current, which does all the heavy lifting of sending the contents of a single MP3 file, skipping the ID3 tag and embedding ICY metadata. The only wrinkle is that you need to keep track of when to send the metadata.

Since you must send metadata chunks at a fixed intervals, regardless of when you happen to switch from one MP3 file to the next, each time you call play-currentyou need to tell it when the next metadata is due, and when it returns, it must tell you the same thing so you can pass the information to the next call to play-current. If play-currentgets NIL from the song source, it returns NIL , which allows the play-songs LOOPto end.

In addition to handling the looping, play-songsalso provides a HANDLER-CASE to trap the error that will be signaled when the MP3 client disconnects from the server and one of the writes to the socket, down in play-current, fails. Since the HANDLER-CASE is outside the LOOP , handling the error will break out of the loop, allowing play-songsto return.

(defun play-songs (stream song-source metadata-interval)

(handler-case

(loop

for next-metadata = metadata-interval

then (play-current

stream

song-source

next-metadata

metadata-interval)

while next-metadata)

(error (e) (format *trace-output* "Caught error in play-songs: ~a" e))))

Finally, you're ready to implement play-current, which actually sends the Shoutcast data. The basic idea is that you get the current song from the song source, open the song's file, and then loop reading data from the file and writing it to the socket until either you reach the end of the file or the current song is no longer the current song.

There are only two complications: One is that you need to make sure you send the metadata at the correct interval. The other is that if the file starts with an ID3 tag, you want to skip it. If you don't worry too much about I/O efficiency, you can implement play-currentlike 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))))

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

(unless (file-position mp3 (id3-size song))

(error "Can't skip to position ~d in ~a" (id3-size song) (file song)))

(loop for byte = (read-byte mp3 nil nil)

while (and byte (still-current-p song song-source)) do

(write-byte byte out)

(decf next-metadata)

when (and (zerop next-metadata) metadata-interval) do

(write-sequence metadata out)

(setf next-metadata metadata-interval))

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

next-metadata)))

This function gets the current song from the song source and gets a buffer containing the metadata it'll need to send by passing the title to make-icy-metadata. Then it opens the file and skips past the ID3 tag using the two-argument form of FILE-POSITION . Then it commences reading bytes from the file and writing them to the request stream. [303] Most MP3-playing software will display the metadata somewhere in the user interface. However, the XMMS program on Linux by default doesn't. To get XMMS to display Shoutcast metadata, press Ctrl+P to see the Preferences pane. Then in the Audio I/O Plugins tab (the leftmost tab in version 1.2.10), select the MPEG Layer 1/2/3 Player ( libmpg123.so ) and hit the Configure button. Then select the Streaming tab on the configuration window, and at the bottom of the tab in the SHOUTCAST/Icecast section, check the "Enable SHOUTCAST/Icecast title streaming" box.

It'll break out of the loop either when it reaches the end of the file or when the song source's current song changes out from under it. In the meantime, whenever next-metadatagets to zero (if you're supposed to send metadata at all), it writes metadatato the stream and resets next-metadata. Once it finishes the loop, it checks to see if the song is still the song source's current song; if it is, that means it broke out of the loop because it read the whole file, in which case it tells the song source to move to the next song. Otherwise, it broke out of the loop because someone changed the current song out from under it, and it just returns. In either case, it returns the number of bytes left before the next metadata is due so it can be passed in the next call to play-current. [304] Folks coming to Common Lisp from Scheme might wonder why play-current can't just call itself recursively. In Scheme that would work fine since Scheme implementations are required by the Scheme specification to support "an unbounded number of active tail calls." Common Lisp implementations are allowed to have this property, but it isn't required by the language standard. Thus, in Common Lisp the idiomatic way to write loops is with a looping construct, not with recursion.

The function make-icy-metadata, which takes the title of the current song and generates an array of bytes containing a properly formatted chunk of ICY metadata, is also straightforward. [305] This function assumes, as has other code you've written, that your Lisp implementation's internal character encoding is ASCII or a superset of ASCII, so you can use CHAR-CODE to translate Lisp CHARACTER objects to bytes of ASCII data.

(defun make-icy-metadata (title)

(let* ((text (format nil "StreamTitle='~a';" (substitute #\Space #\' title)))

(blocks (ceiling (length text) 16))

(buffer (make-array (1+ (* blocks 16))

:element-type '(unsigned-byte 8)

:initial-element 0)))

(setf (aref buffer 0) blocks)

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

Интервал:

Закладка:

Сделать

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

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


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

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

x