<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.linuxformat.ru/wiki/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://wiki.linuxformat.ru/wiki/index.php?action=history&amp;feed=atom&amp;title=LXF84%3APython</id>
		<title>LXF84:Python - История изменений</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.linuxformat.ru/wiki/index.php?action=history&amp;feed=atom&amp;title=LXF84%3APython"/>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/index.php?title=LXF84:Python&amp;action=history"/>
		<updated>2026-05-13T02:38:07Z</updated>
		<subtitle>История изменений этой страницы в вики</subtitle>
		<generator>MediaWiki 1.19.20+dfsg-0+deb7u3</generator>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/index.php?title=LXF84:Python&amp;diff=4900&amp;oldid=prev</id>
		<title>Yaleks: викификация</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/index.php?title=LXF84:Python&amp;diff=4900&amp;oldid=prev"/>
				<updated>2008-06-22T09:31:41Z</updated>
		
		<summary type="html">&lt;p&gt;викификация&lt;/p&gt;
&lt;a href=&quot;http://wiki.linuxformat.ru/wiki/index.php?title=LXF84:Python&amp;amp;diff=4900&amp;amp;oldid=4899&quot;&gt;Внесённые изменения&lt;/a&gt;</summary>
		<author><name>Yaleks</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/index.php?title=LXF84:Python&amp;diff=4899&amp;oldid=prev</id>
		<title>Yaleks: Новая: {{цикл/Python}}  == Python: Обработка графики и звука == ''ЧАСТЬ 4: Язык Python может многое, хотя, конечно, не всё. Но б...</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/index.php?title=LXF84:Python&amp;diff=4899&amp;oldid=prev"/>
				<updated>2008-06-22T09:31:03Z</updated>
		
		<summary type="html">&lt;p&gt;Новая: {{цикл/Python}}  == Python: Обработка графики и звука == &amp;#039;&amp;#039;ЧАСТЬ 4: Язык Python может многое, хотя, конечно, не всё. Но б...&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая страница&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{цикл/Python}}&lt;br /&gt;
&lt;br /&gt;
== Python: Обработка графики и звука ==&lt;br /&gt;
''ЧАСТЬ 4: Язык Python может многое, хотя, конечно, не всё. Но благодаря «привязкам» к таким мощным библиотекам, как GTK и модулям сторонних разработчиков его возможности становятся практически безграничными, пишет '''Сергей Супрунов'''.''&lt;br /&gt;
&lt;br /&gt;
Рассказывать о различных «расширениях» Python можно бесконечно. Чтобы все-таки завершить серию и дать вам возможность погрузиться в самостоятельное изучение этого языка, я&lt;br /&gt;
решил коротко остановиться на двух сторонних библиотеках, значительно расширяющих возможности Python по работе с изображениями и звуком.&lt;br /&gt;
&lt;br /&gt;
=== Где же кружка?... ===&lt;br /&gt;
Начнем с PIL – Python Image Library. Вам наверняка удастся без проблем инсталлировать ее с помощью менеджера пакетов вашего дистрибутива. Не исключено, что она уже установлена (как это имеет&lt;br /&gt;
место быть в Ubuntu). Но если вам не очень повезло (мало ли, вдруг&lt;br /&gt;
вы – фанат Slackware), то забрать архив с ее исходным кодом можно&lt;br /&gt;
на http://www.Pythonware.com.&lt;br /&gt;
&lt;br /&gt;
Итак, зачем она нужна? Представьте, что вы привезли с моря четыре «флешки», забитых замечательными фотографиями, и хотели бы&lt;br /&gt;
згрузить их на свою домашнюю страничку... Начинание благое, но&lt;br /&gt;
каково будет ее посетителям «тянуть» добродушно созданные вашей&lt;br /&gt;
«Минолтой» файлы по 5 МБ каждый? Принципы гуманизма требуют&lt;br /&gt;
предварительно «сжать» изображения до приемлемых размеров. Да&lt;br /&gt;
и миниатюры создать было бы неплохо, чтобы можно было окинуть&lt;br /&gt;
взглядом сразу несколько фотографий.&lt;br /&gt;
&lt;br /&gt;
Если вы уже собрались запускать Gimp – одумайтесь! Ну на 10&lt;br /&gt;
изображений у вас терпения хватит, ну на 100... А если их 1000? Нет,&lt;br /&gt;
ручная работа не для нас. Вот тут-то и пригодится PIL, где уже реализованы широчайшие возможности по обработке изображений.&lt;br /&gt;
&lt;br /&gt;
=== Небольшой практикум ===&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=Листинг conv2.py&lt;br /&gt;
|Содержание=&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; line=&amp;quot;GESHI_NORMAL_LINE_NUMBERS&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
import os, sys, getopt, glob&lt;br /&gt;
import PIL.Image as pim&lt;br /&gt;
type = “JPEG”&lt;br /&gt;
outdir = “.”&lt;br /&gt;
width = height = 0&lt;br /&gt;
opts, pattern = getopt.getopt(sys.argv[1:], “t:o:w:h:”)&lt;br /&gt;
for opt in opts:&lt;br /&gt;
if opt[0] == “-t”: type = opt[1]&lt;br /&gt;
elif opt[0] == “-o”: outdir = opt[1]&lt;br /&gt;
elif opt[0] == “-w”: width = int(opt[1])&lt;br /&gt;
elif opt[0] == “-h”: height = int(opt[1])&lt;br /&gt;
try:&lt;br /&gt;
tmp = pim.new(“RGB”, (1,1))&lt;br /&gt;
tmp.save(“/dev/null”, type)&lt;br /&gt;
except:&lt;br /&gt;
print &amp;gt;&amp;gt; sys.stderr, “ОШИБКА: формат %s не поддерживается” % type&lt;br /&gt;
sys.exit()&lt;br /&gt;
if not pattern: pattern = “.”&lt;br /&gt;
filelist = []&lt;br /&gt;
for entry in pattern:&lt;br /&gt;
if entry[-1] == “/”: entry = entry[:-1]&lt;br /&gt;
if os.path.isdir(entry): entry += “/*”&lt;br /&gt;
filelist.extend(glob.glob(entry))&lt;br /&gt;
for file in filelist:&lt;br /&gt;
if not os.path.isfile(file): continue&lt;br /&gt;
try:&lt;br /&gt;
im = pim.open(file)&lt;br /&gt;
except IOError: continue&lt;br /&gt;
if not (width and height):&lt;br /&gt;
if width: height = width * im.size[1] / im.size[0]&lt;br /&gt;
elif height: width = height * im.size[0] / im.size[1]&lt;br /&gt;
else:&lt;br /&gt;
width = im.size[0]&lt;br /&gt;
height = im.size[1]&lt;br /&gt;
resized = im.resize((width, height), pim.ANTIALIAS)&lt;br /&gt;
name, ext = os.path.splitext(file)&lt;br /&gt;
name = name.split(“/”)[-1]&lt;br /&gt;
outfile = “%s/%s.%s” % (outdir, name, type.lower())&lt;br /&gt;
resized.save(outfile)&lt;br /&gt;
print “%s (%s, %dx%d) -&amp;gt; %s (%s, %dx%d)” % (file,&lt;br /&gt;
im.format, im.size[0], im.size[1],&lt;br /&gt;
outfile, type, width, height)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|Ширина=350px}}&lt;br /&gt;
Итак, после установки библиотеки все ее модули вы, скорее всего,&lt;br /&gt;
найдете в /usr/lib/Python2.4/site-packages/PIL. Кстати, обычно при&lt;br /&gt;
инсталляции PIL добавляет в список sys.path также и указанный путь,&lt;br /&gt;
так что для подключения, скажем, модуля ImageDraw, можно будет&lt;br /&gt;
использовать не только import PIL.ImageDraw, но и просто import&lt;br /&gt;
ImageDraw.&lt;br /&gt;
&lt;br /&gt;
Сами модули не слишком щедро прокомментированы, но зато по&lt;br /&gt;
адресу http://www.Pythonware.com/library/pil/handbook вы найдете превосходное руководство.&lt;br /&gt;
&lt;br /&gt;
Несмотря на множество модулей, входящих в состав библиотеки, для большинства задач вполне хватает модуля Image, а он уже&lt;br /&gt;
сам неявно задействует возможности остальных. Основой является&lt;br /&gt;
объект-изображение, которое можно загрузить из файла (используя&lt;br /&gt;
метод open()), либо создать с нуля (конструктор new()), причем при&lt;br /&gt;
загрузке файла библиотека сама позаботится о распознавании формата изображения.&lt;br /&gt;
&lt;br /&gt;
Для примера напишем небольшой конвертер, который мог бы&lt;br /&gt;
брать указанные с помощью шаблона файлы и сохранять их измененные копии в другом каталоге. PIL предоставляет много методов для&lt;br /&gt;
модификации изображений, в нашем примере мы остановимся на&lt;br /&gt;
двух – изменении размера и формата. Заодно вспомним, как работать&lt;br /&gt;
с файловой системой, и познакомимся с небольшим, но полезным&lt;br /&gt;
модулем getopt для разбора параметров, передаваемых сценарию из&lt;br /&gt;
командной строки. Код сценария представлен в листинге conv2.py.&lt;br /&gt;
&lt;br /&gt;
В строках 8–13 мы используем функцию getopt() одноименного модуля для того, чтобы получить передаваемые в скрипт опции.&lt;br /&gt;
Первым параметром функция получает список аргументов командной строки (без первого элемента, соответствующего имени самого&lt;br /&gt;
скрипта), а вторым – список так называемых «коротких» опций, которые нужно найти. (Модуль поддерживает также и «длинные» опции в&lt;br /&gt;
формате GNU – смотрите документацию или код самого модуля). Если&lt;br /&gt;
опция задается как логическая (т.е. важно лишь то, присутствует ли&lt;br /&gt;
она в командной строке), то в списке просто указывается соответствующая ей буква. Если опция параметрическая (т.е. должна сопровождаться каким-то значением), после ее буквы ставится двоеточие.&lt;br /&gt;
В нашем примере все опции параметрические: -t (формат выходных&lt;br /&gt;
файлов), -o (каталог для их размещения), -h (высота модифицированного изображения), -w (ширина изображения).&lt;br /&gt;
&lt;br /&gt;
Возвращает getopt() два списка: список распознанных опций в&lt;br /&gt;
формате [(опция, значение), (опция, значение), (. . .)] (значение указывается только для параметрический опций, для логических второй&lt;br /&gt;
элемент кортежа остается пустым), и список оставшихся (не распознанных) аргументов. Наш скрипт будет ожидать во втором списке&lt;br /&gt;
имена файлов (с указанием пути, если нужно), которые должны быть&lt;br /&gt;
преобразованы. Пользователь может задать ширину результирующих&lt;br /&gt;
изображений, их высоту или оба параметра сразу (если задан только&lt;br /&gt;
один, второй вычисляется согласно пропорциям исходного файла, см.&lt;br /&gt;
строки 31–36).&lt;br /&gt;
&lt;br /&gt;
Поскольку в опции -t пользователь может ввести все, что угодно, в&lt;br /&gt;
строках 14–19 мы проводим небольшую проверку – создаем изображение размером 1х1 и пытаемся записать его в /dev/null (чтобы нигде&lt;br /&gt;
мусор не разводить) в указанном пользователем формате type (метод&lt;br /&gt;
save() самостоятельно выполняет все нужные преобразования форматов). В случае неудачи сообщаем об этом пользователю (обратите внимание на синтаксис перенаправления вывода по десткриптору, отличному от stdout). Если же операция пройдет успешно – продолжаем.&lt;br /&gt;
&lt;br /&gt;
Строки 20-25 отвечают за формирование списка файлов, соответствующих указанному шаблону. И, начиная с 26-й, мы приступаем собственно к обработке. Файлы, которые не могут быть открыты,&lt;br /&gt;
например, текстовые, мы просто игнорируем – строка 30.&lt;br /&gt;
&lt;br /&gt;
В строке 37 изменяем размер изображения (при этом создается&lt;br /&gt;
новый объект). Флаг Image.ANTIALIAS задает способ интерполяции&lt;br /&gt;
соседних точек (доступны и другие, например, LINEAR, NEAREST,&lt;br /&gt;
BICUBIC). Наконец, рассчитав имя результирующего файла, выполняем сохранение. В данном случае мы не передаем методу save() второй&lt;br /&gt;
параметр, указывающий формат файла – он будет определен автоматически по расширению.&lt;br /&gt;
&lt;br /&gt;
Вот, собственно, и готово:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
admin@toshiba:~/lxf/propy/l4/code$ ./conv2.py -t png -h 120 *.jpg&lt;br /&gt;
osf_t1.jpg (JPEG, 2272x1704) -&amp;gt; ./osf_t1.png (png, 160x120)&lt;br /&gt;
osf_t2.jpg (JPEG, 2272x1704) -&amp;gt; ./osf_t2.png (png, 160x120)&lt;br /&gt;
osf_t3.jpg (JPEG, 2272x1704) -&amp;gt; ./osf_t3.png (png, 160x120)&lt;br /&gt;
osf_t4.jpg (JPEG, 2272x1704) -&amp;gt; ./osf_t4.png (png, 160x120)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Небольшой совет: вместо метода resize() для создания миниатюр&lt;br /&gt;
лучше использовать метод thumbnail() – он работает раза в два быстрее. Только имейте в виду, что thumbnail() изменяет текущий объект,&lt;br /&gt;
т.е. исполняется «по месту», в то время как resize() создает копию объекта, оставляя оригинал в неприкосновенном виде (речь, естественно,&lt;br /&gt;
об объекте в памяти – файл на диске не будет изменен до тех пор, пока&lt;br /&gt;
вы явно не выполните метод save()).&lt;br /&gt;
&lt;br /&gt;
=== Не конвертированием единым... ===&lt;br /&gt;
Естественно, возможности PIL этим не ограничиваются: она позволяет изменять цветовые схемы; применять к изображениям фильтры,&lt;br /&gt;
такие как размывание, рельеф и т.д. (см. модуль ImageFilter и метод&lt;br /&gt;
filter() модуля Image); вы можете смешивать различные изображения&lt;br /&gt;
(методы blend() и composite()), поворачивать их на различные углы,&lt;br /&gt;
смещать, вырезать из них фрагменты, накладывать простейшие графические элементы (такие как линии и дуги, см. модуль ImageDraw),&lt;br /&gt;
и т.д.&lt;br /&gt;
&lt;br /&gt;
Вот так, например, можно в два раза усилить «красную» составляющую исходного изображения:&lt;br /&gt;
&lt;br /&gt;
ЛИСТИНГ MAXIRED.PY&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/Python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import os, sys, Image&lt;br /&gt;
&lt;br /&gt;
infile = sys.argv[1]&lt;br /&gt;
im = Image.open(infile)&lt;br /&gt;
if im.mode == “RGB”:&lt;br /&gt;
 imR, imG, imB = im.split()&lt;br /&gt;
 imR = imR.point(lambda pixel: pixel * 2)&lt;br /&gt;
 outfile = Image.merge(“RGB”, (imR, imG, imB))&lt;br /&gt;
 outfile.save(“%s-red%s” % os.path.splitext(infile))&lt;br /&gt;
else:&lt;br /&gt;
 print &amp;gt;&amp;gt; sys.stderr, “ОШИБКА: файл не RGB”&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Здесь методом split() мы раскладываем исходный объект на «цветовые» составляющие (если атрибут объекта, mode, подтверждает,&lt;br /&gt;
что загруженный файл является RGB-изображением), методом point()&lt;br /&gt;
применяем указанную функцию (в нашем случае - умножение на два)&lt;br /&gt;
к каждому пикселу «красного» объекта, и с помощью merge() объединяем все снова в одно изображение.&lt;br /&gt;
&lt;br /&gt;
Нужно заметить, что библиотека PIL предназначена для обработки&lt;br /&gt;
изображений, а не для их вывода. Если вы хотите вставить фотографию в ваше графическое приложение, для этого следует использовать средства соответствующего модуля. Например, в Tkinter для этого&lt;br /&gt;
предназначены классы BitmapImage и PhotoImage. Есть, конечно, и в&lt;br /&gt;
PIL метод show(), но он просто сохраняет объект во временный файл&lt;br /&gt;
и отдает его внешней программе просмотра изображений (xv под Unix/Linux, Paint в Windows), поэтому пригоден он разве что для отладочных целей, чтобы по ходу разработки скрипта можно было «на лету»&lt;br /&gt;
контролировать промежуточные результаты.&lt;br /&gt;
&lt;br /&gt;
=== Нам песня строить и жить помогает... ===&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=Листинг «playit.py»&lt;br /&gt;
|Содержание=&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; line=&amp;quot;GESHI_NORMAL_LINE_NUMBERS&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
import pymedia.audio.acodec as acodec&lt;br /&gt;
import pymedia.audio.sound as sound&lt;br /&gt;
import pymedia.muxer as muxer&lt;br /&gt;
import time&lt;br /&gt;
class playit:&lt;br /&gt;
def __init__(self, file2play, rateCf=1):&lt;br /&gt;
self.PLAY_FLG = 1&lt;br /&gt;
self.file2play = file2play&lt;br /&gt;
self.rateCf = rateCf&lt;br /&gt;
def playit(self):&lt;br /&gt;
dm = muxer.Demuxer(self.file2play.split(‘.’)[-1].lower())&lt;br /&gt;
f = open(self.file2play, ‘rb’)&lt;br /&gt;
s = f.read(32000)&lt;br /&gt;
dm.parse(s)&lt;br /&gt;
dec = acodec.Decoder({‘id’:dm.streams[0][‘id’]})&lt;br /&gt;
r = dec.decode(s)&lt;br /&gt;
print ‘Play “%s”:’ % self.file2play&lt;br /&gt;
print ‘ Bitrate: %d’ %r.bitrate&lt;br /&gt;
print ‘ Sample Rate: %d’ % r.sample_rate&lt;br /&gt;
print ‘ RateCf: %.2f’ % self.rateCf&lt;br /&gt;
print ‘ Channels: %d’ % r.channels&lt;br /&gt;
snd = sound.Output(int(r.sample_rate * self.rateCf),&lt;br /&gt;
r.channels,&lt;br /&gt;
sound.AFMT_S16_LE)&lt;br /&gt;
while len(s) &amp;gt; 0:&lt;br /&gt;
if r: snd.play(r.data)&lt;br /&gt;
s = f.read(512)&lt;br /&gt;
r = dec.decode(s)&lt;br /&gt;
while snd.isPlaying(): time.sleep(1)&lt;br /&gt;
self.PLAY_FLG = 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|Ширина=350px}}&lt;br /&gt;
Следующая библиотека, которую мы затронем в этом уроке – PyMedia.&lt;br /&gt;
Скачать исходный код можно с сайта http://www.pymedia.org (там же вы найдете и документацию, и архив с примерами). Установка выполняется,&lt;br /&gt;
в принципе, достаточно просто:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
admin@toshiba:~$ tar xzvf PyMedia-1.3.7.3.tar.gz&lt;br /&gt;
admin@toshiba:~$ cd PyMedia-1.3.7.3&lt;br /&gt;
admin@toshiba:~/PyMedia-1.3.7.3$ sudo Python setup.py install&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Однако, среди зависимостей – alsa, ogg, vorbis, faad, mp3lame&lt;br /&gt;
(причем для инсталляции нужны и заголовочные файлы, т.е. может&lt;br /&gt;
потребоваться доустановить соответствующие dev-пакеты). Также&lt;br /&gt;
потребуется пакет Python-dev. Так что, если вам посчастливится&lt;br /&gt;
найти для своего дистрибутива двоичный пакет библиотеки (в частности, deb-пакет, правда, не самой новой версии, можно найти&lt;br /&gt;
здесь: http://prdownloads.sourceforge.net/PyMedia/PyMedia_1.3.5_i686-py2.4.deb?download), то рекомендую воспользоваться им.&lt;br /&gt;
&lt;br /&gt;
На листинге «playit.py» представлен код класса, задача которого –&lt;br /&gt;
воспроизвести звуковой файл. Первыми строками (3–6) подключаем&lt;br /&gt;
нужные нам модули (иерархия здесь довольно сложная, так что без&lt;br /&gt;
документации не обойтись; ну и про примеры не забывайте).&lt;br /&gt;
&lt;br /&gt;
Сначала мы должны определить идентификатор кодека, который&lt;br /&gt;
подойдет для воспроизведения того или иного файла. Для этого мы&lt;br /&gt;
создаем объект Demuxer, которому передается в качестве параметра&lt;br /&gt;
расширение файла (строка 13). Этот объект мы используем для того,&lt;br /&gt;
чтобы декодировать заголовок звукового файла (в строках 14–16 мы&lt;br /&gt;
считываем первые 32000 байт файла и передаем их методу parse()).&lt;br /&gt;
Теперь мы можем определить идентификатор нужного кодека по ключу ‘id’ в словаре dm.streams[0] (строка 17; можно в качестве параметра&lt;br /&gt;
передать и весь словарь), и используем этот кодек для декодирования&lt;br /&gt;
уже считанных данных. Поскольку здесь, помимо всего прочего, присутствует и служебная информация, то после декодирования мы получаем возможность вывести кое-что из этого на экран (строки 19–23;&lt;br /&gt;
но это только в тестовых целях – в классах, которые могут использоваться в различных программах, оператору print, конечно, не место).&lt;br /&gt;
&lt;br /&gt;
В строке 24 создается объект Output, метод play() которого будет&lt;br /&gt;
использоваться для воспроизведения (строка 28). Изменив параметр&lt;br /&gt;
rateCf, можно ускорить или замедлить проигрывание файла (по умолчанию используется значение 1). Наконец, в цикле (строки 27–30) мы&lt;br /&gt;
воспроизводим уже считанный фрагмент (переменная s) и готовим&lt;br /&gt;
следующий. Как только мы считаем и передим методу play() весь&lt;br /&gt;
файл, в строке 31 начнется ожидание конца воспроизведения (что-бы не сильно нагружать процессор, проверку выполняем один раз в&lt;br /&gt;
секунду). Ожидание нужно, поскольку play() является асинхронным&lt;br /&gt;
методом, который возвращает управление сценарию до того, как воспроизведение фрагмента на самом деле завершится. Благодаря этому&lt;br /&gt;
мы можем спокойно обрабатывать следующий фрагмент, не беспокоясь о паузах при воспроизведении.&lt;br /&gt;
&lt;br /&gt;
Для использования класса playit нужно создать соответствующий объект, передав ему имя файла и, при желании, коэффициент,&lt;br /&gt;
корректирующий скорость воспроизведения. Само воспроизведение&lt;br /&gt;
запускается методом playit(). Причем библиотека PyMedia вполне&lt;br /&gt;
позволяет поигрывать одновременно несколько файлов - в качестве&lt;br /&gt;
примера рассмотрим, как можно получить простейший эффект объемного звука:&lt;br /&gt;
&lt;br /&gt;
Листинг echo.py&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/Python&lt;br /&gt;
from playit import playit&lt;br /&gt;
import threading, time&lt;br /&gt;
mp3 = ‘Aria.shtil.mp3’&lt;br /&gt;
ECHO = 0.1&lt;br /&gt;
f1 = playit(mp3)&lt;br /&gt;
f1.rateCf = 1&lt;br /&gt;
ht1 = threading._start_new_thread(f1.playit, ())&lt;br /&gt;
if ECHO:&lt;br /&gt;
time.sleep(ECHO)&lt;br /&gt;
f2 = playit(mp3)&lt;br /&gt;
f2.rateCf = 1&lt;br /&gt;
ht2 = threading._start_new_thread(f2.playit, ())&lt;br /&gt;
while(f1.PLAY_FLG or ECHO and f2.PLAY_FLG):&lt;br /&gt;
time.sleep(1)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В этом сценарии мы запускаем два потока (если значение переменной ECHO отлично от нуля). В каждом из потоков проигрывается один&lt;br /&gt;
и тот же файл, но перед запуском второго делается небольшая пауза&lt;br /&gt;
(в примере – 0,1 секунды). В результате получается довольно интересное звучание. Кстати, обратите внимание на то, как мы запустили потоки – вместо того, чтобы создавать соответствующий класс и переопределять в нем метод run(), был напрямую вызван «внутренний» метод&lt;br /&gt;
_start_new_thread(), которому передается функция или метод, которые&lt;br /&gt;
должны быть выполнены в потоке.&lt;br /&gt;
&lt;br /&gt;
Помимо собственно воспроизведения звука, PyMedia предоставляет средства для работы с видео-файлами, ее можно использовать для&lt;br /&gt;
конвертирования исходного файла в другие форматы, для редактирования мета-данных и самого звука, и т.д.&lt;br /&gt;
&lt;br /&gt;
=== Малышка wave ===&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=Листинг wav2.py&lt;br /&gt;
|Содержание=&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; line=&amp;quot;GESHI_NORMAL_LINE_NUMBERS&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
import wave&lt;br /&gt;
def sum(a, b):&lt;br /&gt;
return “%c%c” % (a, b)&lt;br /&gt;
rf = wave.open(“new.wav”, “rb”)&lt;br /&gt;
print “Количество фреймов: %d “ % rf.getnframes()&lt;br /&gt;
print “Частота дискретизации: %d” % rf.getframerate()&lt;br /&gt;
print “Точность дискретизации: %d” % rf.getsampwidth()&lt;br /&gt;
print “Количество каналов: %d” % rf.getnchannels()&lt;br /&gt;
print “Тип сжатия: %s” % rf.getcomptype()&lt;br /&gt;
total = rf.getnframes() * rf.getnchannels() * rf.getsampwidth()&lt;br /&gt;
normal = rf.readframes(total)&lt;br /&gt;
reverse = ‘’&lt;br /&gt;
if rf.getsampwidth() == 2:&lt;br /&gt;
n2 = normal[-2::-2]&lt;br /&gt;
n1 = normal[-1::-2]&lt;br /&gt;
for i in map(sum, n0, n1):&lt;br /&gt;
reverse += i&lt;br /&gt;
else:&lt;br /&gt;
reverse = normal[-1::-1]&lt;br /&gt;
wf = wave.open(“new2.wav”, “wb”)&lt;br /&gt;
wf.setnchannels(rf.getnchannels())&lt;br /&gt;
wf.setsampwidth(rf.getsampwidth())&lt;br /&gt;
wf.setframerate(rf.getframerate())&lt;br /&gt;
wf.writeframes(reverse)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|Ширина=350px}}&lt;br /&gt;
Кстати, раз уж зашла речь об обработке звука, то и в стандартной&lt;br /&gt;
поставке Python есть несколько модулей для выполнения простейших&lt;br /&gt;
операций. Например, модуль wave позволяет редактировать (и даже&lt;br /&gt;
создавать с нуля, если вы сильны в математике) звуковые файлы в&lt;br /&gt;
формате WAV. На листинге wav2.py представлен сценарий, с помощью&lt;br /&gt;
которого можно «развернуть» wav-файл в обратном направлении:&lt;br /&gt;
&lt;br /&gt;
Открыв wav-файл (строка 6), мы можем получить некоторую&lt;br /&gt;
информацию о нем (строки 7-11). Считываем данные в переменную&lt;br /&gt;
normal (нормальная последовательность). «Сырой» wav-файл (т.е. без&lt;br /&gt;
компрессии; подавляющее большинство таковыми и является) представляет собой набор «фреймов», или «отсчетов», то есть значений&lt;br /&gt;
амплитуды сигнала в данный момент времени. Частота дискретизации&lt;br /&gt;
определяет, сколько фреймов будут формировать одну секунду звучания. Точность дискретизации показывает, сколько байт используется для хранения одного фрейма (значение 1 соответствует 8-битному&lt;br /&gt;
звуку, 2 – 16-битному).&lt;br /&gt;
&lt;br /&gt;
Для того чтобы развернуть наш файл, нужно «реверсировать» считанную нормальную последовательность. Это можно легко выполнить&lt;br /&gt;
с помощью списковых включений (как показано в строке 21). Но если&lt;br /&gt;
мы работаем с 16-битным файлом, то нужно позаботиться о сохранении порядка байтов во фрейме, иначе получим лишь шум. Для этого в&lt;br /&gt;
строках 16 и 17 мы формируем две «подпоследовательности», в одну&lt;br /&gt;
из которых попадают младшие байты фреймов, во вторую – старшие.&lt;br /&gt;
С помощью функции map(), которая применяет функцию, указанную&lt;br /&gt;
первым параметром (в нашем примере это sum(), описанная в строках&lt;br /&gt;
4–5), к каждому элементу последовательностей, переданных вторым и&lt;br /&gt;
третьим параметрами, мы соединяем полученные полуфреймы воедино. Поскольку на выходе map() получается список, то нам нужно его&lt;br /&gt;
вручную «собрать» снова в строку (стр. 18–19).&lt;br /&gt;
&lt;br /&gt;
Нужно заметить, что map() отличается очень высокой скоростью&lt;br /&gt;
обработки последовательностей. Если собирать результирующую&lt;br /&gt;
строку «вручную» (например, в цикле while), то эта процедура может&lt;br /&gt;
затянуться на десятки секунд даже для не очень большого файла, в то&lt;br /&gt;
время как map() выполняет эту операцию почти мгновенно.&lt;br /&gt;
&lt;br /&gt;
Наконец, в строках 22-26 мы открываем новый файл на запись,&lt;br /&gt;
устанавливаем его параметры (в соответствии с исходными) и записываем содержимое. Теперь можете и сами поиграть в «АПОП»!&lt;br /&gt;
&lt;br /&gt;
=== Только вперед! ===&lt;br /&gt;
{{Врезка|left|&lt;br /&gt;
|Заголовок=Cсылки по теме&lt;br /&gt;
|Содержание=&lt;br /&gt;
* [http://www.python.org www.python.org] – официальный сайт проекта&lt;br /&gt;
* [http://www.python.ru www.python.ru] – российский сайт почитателей этого языка&lt;br /&gt;
* [http://zope.net.ru zope.net.ru] – сайт российской группы пользователей среды Zope (разработанный на Python сервер web-приложений); здесь есть информация и о Python&lt;br /&gt;
* [http://www.pythonware.com www.pythonware.com] – сайт разработчиков PIL; помимо самой библиотеки, можно найти и другие интересные вещи&lt;br /&gt;
* [http://www.awaretek.com/plf.html www.awaretek.com/plf.html] – страничка, посвящённая изучению языка Python&lt;br /&gt;
* [http://py.vaults.ca/apyllo.py py.vaults.ca/apyllo.py] – множество примеров программ на Python, от работы с базами данных и графикой до игр&lt;br /&gt;
|Ширина=350px}}&lt;br /&gt;
На этом мы завершаем нашу серию уроков. Благодаря тому, что разработчикам Python удалось сделать этот язык простым и в то же время&lt;br /&gt;
удивительно мощным и расширяемым, с его помощью можно эффективно решать самые различные задачи – дополнительная сложность&lt;br /&gt;
будет проявляться лишь там, где это действительно необходимо, в&lt;br /&gt;
то время как простые задачи сохранят предельную простоту. И если&lt;br /&gt;
вдруг для какого-то проекта стандартных средств окажется недостаточно, то наверняка вам поможет какая-нибудь из сторонних библиотек. Главное – не сдаваться!&lt;br /&gt;
&lt;br /&gt;
Удачи!&lt;/div&gt;</summary>
		<author><name>Yaleks</name></author>	</entry>

	</feed>