Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Обзор элементов языка программированияСтр 1 из 3Следующая ⇒
Общая часть Обзор элементов языка программирования
Что представляет собой звук? Свое знакомство с программированием звука на Турбо Паскале мы начнем с использования встроенного динамика. Прежде всего замечу, что модуль Crt содержит две процедуры, предназначенные для работы с динамиком. Первая из них- Sound(Hz) - включает динамик на звуковой частоте, задаваемой значением параметра Hz (типа Word) в герцах. Динамик генерирует звук до тех пор, пока он не будет отключен вызовом процедуры NoSound, не имеющей параметров Процедура Sound обеспечивает довольно бедную интонацию, потому что она использует только целочисленные частоты. Да и встроенный динамик, к сожалению, дает звук самого низкого качества Он не допускает управления громкостью, очень по-разному резонирует на разных частотах. Не ждите от него многого' Тем не менее, мы постараемся хотя бы частично исправить положение и разработаем свои собственные процедуры для модуля Speaker. Прежде всего, познакомимся поближе с работой встроенного динамика. Источником звуковых акустических колебаний является его диффузор. Он может находиться в одном из двух возможных положений. Для управления работой динамика ему посылаются прямоугольные импульсы определенной частоты. В течение первой половины каждого цикла диффузор перемещается в одно положение, а затем, в течение второй половины цикла, в другое. Это вызывает движение воздуха. В процессе генерации акустических колебаний прямоугольный импульс, который порождает неприятно звучащую ноту, несколько сглаживается. Так возникает звуковой сигнал. Теперь несколько слов о технических деталях. Компьютер содержит микросхему 8255, которую называют «программируемым периферийным интерфейсом» (PPI — Programmable Peripheral Interface). PPI управляет работой динамика, используя микросхему таймера 8254 (PIT — Programming Interval Timer). Микросхема 8255 имеет различные порты, включая порт ввода\вывода $61 размером («шириной») в один байт с битами b7…b0. Запись в порт $61 нулевого либо единичного значения бита b0 позволяет установить режим управления динамиком. Если b0 = 1, то динамиком управляет второй канал микросхемы таймера. Микросхема таймера имеет 3 канала, каждый из которых предназначен для решения своих задач. Нулевой канал обслуживает системные часы, первый канал обслуживает микросхему прямого доступа к памяти (DMA). Второй канал связан со встроенным динамиком. Обычно он запрограммирован на генерацию последовательности прямоугольных импульсов, что дает при включении динамика непрерывный тон определенной частоты. Управление встроенным динамиком связано прежде всего с программированием второго канала таймера. Для работы с таймером используются порты (всего 4), на которых для нас интерес представляют порт $42 (порт второго канала таймера) и порт $43 (порт управляющего слова — открыт только для записи). Каждый канал имеет свой | ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 07.12.09. |
6 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
счетчик, содержимое которого уменьшается от некоторого максимального значения. Для второго канала определена константа $1234DD. Это значение представляет собой число, которое нужно разделить на частоту в герцах, чтобы получить значение счётчика для таймера. Итак, мы выяснили, что единичное значение управляющего бита b0 означает, что динамик подключён к каналу, а нулевое значение – что он отключён от канала. Динамик включён, если бит b1равен единице. Таким образом, прежде всего надо научиться «включать» биты b0 и b1, записывая в них единичные значение, не изменяя значений всех прочих битов. Чтобы сообщить таймеру о том, что следующие два байта являются значением типа Word, обратно пропорциональным частоте, и что на выходе должен быть прямоугольный импульс, в порт микросхемы таймера $43 должно быть записано значение $86. После этого таймер будет включать и выключать динамик с определённой частотой. | ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г. К. | 07.12.09. |
7 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
Специальная часть Общая постановка задачи Темой данной курсовой работы, который был выполнен в ходе изучения курса “Основы алгоритмизации и программирования” является, - «Обработка потока, поступающего с видео и аудио устройства». Далее мы обсудим: что такое DirectShow, для чего он предназначен, как он работает и рассмотрим технологию программирования звука. Потом нам предстоит написать программу, которая генерирует последовательности прямоугольных звуковых импульсов (стр. 21-22) DirectShow – это архитектура для воспроизведения, перехвата и обработки потоков мультимедиа. С помощью этого API можно: · проигрывать мультимедийные файлы различного формата, такие как MPEG (Motion Picture Experts Group), AVI (Audio-Video Interleaved), MP2 (MPEG Audio Layer-2), DVD и конечно WAV; · перехватывать видео-поток с различного рода TV-карт, видеокамер и т.п.; · создавать нестандартные обработчики мультимедиа-потоков и свои собственные форматы файлов; · обращаться непосредственно к видео и аудио потокам, чтобы выводить их на Surface DirectDraw. DirectShow интегрирован с DirectX так, что использует DirectDraw и DirectSound для вывода изображения и звука, и, при наличии аппаратного ускорения, автоматически им воспользуется. В концепции DirectShow мультимедийные данные – это поток, который проходит через несколько обрабатывающих блоков. Блоки, обрабатывающие поток данных, передают данные по цепочке друг другу, таким образом можно представить себе несколько “устройств”, каждое из которых выполняет какую-то обработку данных и передает их соседнему “устройству”. Эти “устройства” или “блоки обработки” данных называют фильтрами. Цепочка, по которой передаются данные, содержит несколько фильтров, связанных определенным образом. В DirectShow имеются готовые фильтры, из которых, словно из детских кубиков, программист может выстроить ту или иную цепочку обработку данных, кроме того, конечно, можно создать свои, нестандартные фильтры. Для создания такой “цепочки обработки” (которая, кстати, официально называются Filter Graph – “граф фильтров” или, в несколько вольном переводе - “схема соединения фильтров”), так вот для создания схемы соединения фильтров, предназначен самый базовый и лежащий в основе всех основ компонент DirectShow, под названием Filter Graph Manager – Менеджер Графа Фильтров. Например, программа показывающая видео из AVI-файла может построить такой граф фильтров:
| ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 07.12.09 |
8 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
В этом примере пять фильтров, первый (File Source) просто читает данные с диска, второй фильтр (AVI Splitter) разделяет данные на кадры и передает упакованные видео данные фильтру AVI Decompressor, который их распаковывает и передает фильтру Default DirectSound Device, выводящему звук. AVI Decompressor передает распакованные данные фильтру Video Renderer, который выводит кадры видео на экран. Фильтры делятся на три типа: Фильтры-источники (Source filters) - эти фильтры просто получают данные из какого-то источника, с диска (как фильтр File Source (Async) на рисунке), с CD или DVD дисковода или с TV – карты или карты, к которой подключена цифровая видеокамера. Фильтры-преобразователи (Transform filters) – эти фильтры как видно из названия преобразуют поток данных, проходящий через них каким-либо образом, например – разделяет поток данных на кадры, производят декомпрессию и т.п. На нашем рисунке к таким фильтрам относятся AVI Splitter и AVI Decompressor. Фильтры вывода (Renderer filters) – фильтры, которые получают полностью обработанные данные и выводят их на монитор, звуковую карту, пишут на диск или выводят на еще какое-нибудь устройство. Итак из фильтров-кубиков можно выстраивать граф. Делается это с помощью интерфейса IGraphBuilder. Создать объект типа IGraphBuilder можно так:
CoCreateInstance ( CLSID _ FilterGraph, nil , CLSCTX _ INPROC _ SERVER, IID _ IG raphBuilder, MyGraphBuilder );
Здесь переменная MyGraphBuilder имеет тип IGraphBuilder; идентификатор класса CLSID_FilterGraph и IID_IGraphBuilder обьявлены в файле DShow.pas, поэтому не забудьте добавить: uses DShow.pas Итак, интерфейс IGraphBuilder получен. Можно построить граф фильтров, такой, какой нам нужно. Впрочем, все не так сложно, IGraphBuilder достаточно интеллектуален, он может сам, автоматически, построить граф, в зависимости от того какие файлы мы собираемся воспроизводить. Интерфейс IGraphBuilder имеет метод RenderFile, который получает имя файла в качестве параметра и, в зависимости от типа файла (которое определяется по расширению и по специальным сигнатурам в файле), сканирует реестр, в поисках необходимой для построения графа информации, создает необходимые фильтры и строит | ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г. К. | 07.12.09. |
9 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
граф, предназначенный для воспроизведения файлов этого типа (WAV, AVI, MP2, MPG и т.д.).
Описание программ комплекса После построения графа, DirectShow готов к воспроизведению. Для управления потоком данных через граф обработки предназначен интерфейс IMediaControl – он имеет методы Run, Pause и Stop.
Пример:
Uses ... DShow, ActiveX, ComObj; Var MyGraphBuilder: IGraphBuilder; MyMediaControl: IMediaControl; Begin CoInitialize(nil); { получаем интерфейс IGraphBuilder} CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER, IID_I GraphBuilder, MyGraphBuilder); {вызываем RenderFile - граф фильтров строится автоматически} MyGraphBuilder.RenderFile(cool.avi', nil); { получаем интерфейс ImediaControl} MyGraphBuilder.QueryInterface(IID_IMediaControl, MyMediaControl); { Примечание - MyMediaControl - переменная типа IMediaControl} {проигрываем видео} MyMediaControl.Run; {ждем пока пользователь не нажмет ОК (видео воспроизводится в отдельном ( thread ) потоке)} ShowMessage(' Нажмите O К '); CoUninitialize; End; Интерфейс IVideoWindow содержит методы для управления заголовком, стилем, местоположением и размерами окошка в котором проигрывается видео. Давайте попробуем переделать наш пример так, чтобы видео выводилось не в отдельном окошке, а, скажем на компоненте TPanel, расположенном в нашей форме. Добавьте на форму компонент TPanel, пусть он называется Panel1.
| ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | ЕнсеповаГ.К. | 07.12.09 |
10 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
Uses ... DShow, ActiveX, ComObj; procedure TForm1.Button1Click(Sender: TObject); Var MyGraphBuilder: IGraphBuilder; MyMediaControl: IMediaControl; VideoWindow: IVideoWindow; Begin CoInitialize(nil); {получаем интерфейс IGraphBuilder} CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER, IID_I GraphBuilder, MyGraphBuilder); {вызываем RenderFile - граф фильтров строится автоматически} MyGraphBuilder.RenderFile('C: \Program Files\Borland\Pascal\Demos\Coolstuf\cool.avi', nil); {получаем интерфейс ImediaControl} MyGraphBuilder.QueryInterface(IID_IMediaControl, MyMediaControl); { Примечание - MyMediaControl - переменная типа IMediaControl} {получаем интерфейс IVideoWindow} MyGraphBuilder.QueryInterface(IID_IVideoWindow, VideoWindow); { Примечание - VideoWindow - переменная типа IVideoWindow} {располагаем окошко с видео на панель} VideoWindow.Set_Owner(Self.Panel1.Handle); VideoWindow.Set_WindowStyle(WS_CHILD OR WS_CLIPSIBLINGS); VideoWindow.SetWindowPosition(0, 0, Panel1.ClientRect.Right, Panel1.ClientR ect.Bottom); {проигрываем видео} MyMediaControl.Run; ShowMessage('Нажмите OК'); CoUninitialize; end ; Программа Speaker1 предназначена для генерации последовательности прямоугольных звуковых импульсов: Двоичное представление шестнадцатеричного значения #FC имеет вид 11111100. Вначале определяются значение, находящееся в порте динамика, и два младших бита обнуляются (благодаря использованию операции and и маски $FC). В цикле динамик включается (в бит b1 записывается единица), затем, после небольшой задержки, отключается и так повторяется до нажатия произвольной | ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 07.12.09. |
11 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
клавиши. После нажатия клавиши выполнение цикла прекращается. Важно то, что оба младших бита будут содержать нулевые значения, и при всех последующих обращениях к динамику других программ он будет работать правильно. Программа генерирует тон частотой примерно 100Гц.
Таблица идентификаторов комплекса
Для написания программы Speaker1, мы использовали следующие идентификаторы:
| ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 07.12.09. |
13 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
Описание наборов данных В основе иерархии классов, обеспечивающих функционирование наборов данных в приложениях баз данных, лежит класс TDataSet. Хотя он почти не содержит методов, реально обеспечивающих работоспособность основных механизмов набора данных, тем не менее его значение трудно переоценить. Этот класс задает структурную основу функционирования набора данных. Другими словами, это скелет набора данных, к методам которого необходимо лишь добавить требуемые вызовы соответствующих функций реальных технологий. При решении наиболее распространенных задач программирования в процессе создания приложений баз данных класс TDataSet не нужен. Тем не менее знание основных принципов работы набора данных всегда полезно. Кроме этого, класс TDataSet может использоваться разработчиками в качестве основы для создания собственных компонентов. Поэтому рассмотрим основные механизмы, реализованные в наборе данных.
Структура записей файлов Multimedia Streaming – это архитектура, используемая в DirectShow для облегчения жизни программиста. Эта архитектура позволяет работать с мультимедиа данными, как с абстрактным потоком, не вдаваясь в подробности форматов хранения мультимедиа-файлов или специфику устройств-источников мультимедиа. Используя эту архитектуру, программист концентрируется не на расшифровке и преобразовании данных, а на управлении потоком данных, кадрами видео или аудио семплами. На вершине иерархии находится базовый объект Multimedia Stream, который является контейнером для объектов Media Stream. Объект Multimedia Stream может содержать один или несколько объектов Media Stream. В то время как каждый объект типа Media Stream предназначен для работы с данными какого-то одного типа (видео, аудио и т.п.) – Multimedia Stream – просто содержит методы для обращения к содержащимся в нем объектам Media Stream и не зависит от типа данных. Сейчас мы создадим объект типа IAMMultiMediaStream. Этот интерфейс унаследован от IMultimediaStream и содержит, кроме прочего, функцию OpenFile, которая автоматически строит граф фильтров для воспроизведения файла: CoCreateInstance ( CLSID _ AMMultiMediaStream, nil, CLSCTX _ INPROC _ SE RVER, IID _ IAMMultiMediaStream, AMStream ); Здесь переменная AMStream имеет тип IAMMultiMediaStream. Мы создали контейнер для мультимедийных потоков. Сверяемся с рисунком - мы на верхнем уровне иерархии. У нас есть объект типа IMultimediaStream – теперь в этот контейнер нужно проинициализировать и добавить один или несколько мультимедиа потоков, нужного нам типа. Сначала инициализация: AMStream.Initialize(STREAMTYPE_READ, AMMSF_NOGRAPHTHREAD, nil); | ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 07.12.09. |
14 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
При инициализации указываем, что будут создаваться мультимедиа потоки для чтения, передав значение STREAMTYPE_READ (другие варианты STREAMTYPE_WRITE, STREAMTYPE_TRANSFORM). Создадим теперь мультимедиа потоки для видео и звука: AMStream.AddMediaStream(DDraw, MSPID_PrimaryVideo, 0, NewMediaStremVideo); AMStream.AddMediaStream(nil, MSPID_PrimaryAudio, AMMSF_ADDDEFAULTRENDERER, NewMediaStremAudio); Вызываем метод OpenFile – файл загружается, и автоматически строится граф фильтов: AMStream.OpenFile('cool.avi', 0); Осталось направить видео поток мультимедиа поток на Surface. Вот процедура, которая делает это: procedure TForm1.RenderStreamToSurface(Surface: IDirectDrawSurface; MMStream: IMultiMediaStream); Var PrimaryVidStream: IMediaStream; DDStream: IDirectDrawMediaStream; Sample: IDirectDrawStreamSample; RECT: TRect; ddsd: TDDSURFACEDESC; Z: DWORD; Begin MMStream.GetMediaStream(MSPID_PrimaryVideo, PrimaryVidStream); PrimaryVidStream.QueryInterface(IID_IDirectDrawMediaStream, DDStream); ddsd.dwSize: = sizeof(ddsd); DDStream.GetFormat(ddsd, Palitra, ddsd, Z); rect.top: =(480-ddsd.dwHeight)div 2; rect.left: =(640 - ddsd.dwWidth) div 2; rect.bottom: = rect.top+ddsd.dwHeight; rect.right: = rect.left+ddsd.dwWidth; DDStream.CreateSample(Surface, Rect, 0, Sample); MMStream.SetState(STREAMSTATE_RUN); end ; Метод IDirectDrawStreamSample.Update выводит очередной кадр на Surface. При достижении конца потока он вернет ошибку с кодом $40002 (MS_S_ENDOFSTREAM), я в этом случае просто перематываю поток к началу, методом Seek. В этой программе инициализируется DirectDraw, создается Surface, а затем на него выводится видео из avi-файла. | ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 07.12.09. |
15 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
Организация производства Заключение
Выполняя нашу курсовую работу, мы задались целью выяснить, какие есть способы программирование звука и видео и по возможности внести что-то свое. Выяснив, что на данный момент существует несколько способов программирование звука, мы решили написать программу звука на языке Турбо Паскаль. В этой курсовой работе мы описали в основном 3 программы: speaker1, speaker2 и zvuko_zapis. В основу разработанной программы звука на языке Турбо Паскаль заложена программа speaker1 предназначенная для генерации последовательности прямоугольных звуковых импульсов и его улучшенный вариант - программа speaker2. Учтено, что манипуляции с мышью не должно приводить к прерывистому звучанию динамика, и использовано вещественное значение частоты, а также программа zvuko_zapis, предназначенный для записи звука и приёма и показа звука с одного из входов. Также рассмотрена работа DirectShow, для чего он предназначен и как он воспроизводит видео форматы. Рассмотрев много языков программирования, которые позволяют осуществлять программирование звука и видео, мы остановили свой выбор на языке Турбо Паскаль. Выполненное работа дает возможность использование программу, как преподавателям, так и студентам, для этого достаточно лишь установить данную программу на компьютер.
| ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 0 7.12.09. |
20 | |||||||||||||||||
изм | Лист | № докум | Подпись | Дата | ||||||||||||||||
Приложения Приложение А Текст программы speaker 1
Листинг:
Program speaker 1; Uses crt; Const Speaker_port = %61; Var Portval: byte;
Begin Portval: = port[speaker_port] and $FC; While not KeyPressed do begin Port[speaker_port]: = portval or 2; Delay(5); Port[speaker_port]: = portval; Delay(5); End; ReadKey; End.
| ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г. К. | 0 7.12.09. |
21 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
Приложение Б Текст программы speaker 2 Листинг:
Program speaker 2; Uses crt; Const Speaker_port = $61; Pit_control = $42; Pit_channel_2 = $42; Pit_freq = $1224dd; Procedure sound (frequency: word); Var Counter: word; Begin Counter: = pit_freq div frequency; Port[pit_control]: = $b6; Port[pit_channel_2]: = lo(counter); Port[pit_channel_2]: = hi(counter); Port[speaker_port]: = port[speaker_port] or 2; End; Procedure nosound; Begin Port[speaker_port]: = port[speaker_port] and $fc; End; Begin Sound(200); Repeat until keypressed; Nosound; End. | ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 07.12.09. |
22 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
Приложение В Текст программы Листинг:
unit zvuko_zapis;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls, MMSystem, Buttons;
type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Label1: TLabel; Image1: TImage; Button2: TButton; Label2: TLabel; BitBtn1: TBitBtn; CheckBox1: TCheckBox; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure Button2Click(Sender: TObject); procedure BitBtn1Click(Sender: TObject); private { Private declarations } public procedure OnWaveIn(var Msg: TMessage); message MM_WIM_DATA; { Public declarations } end;
TData16 = array [0..127] of smallint; PData16 = ^TData16; tWaveFileHdr = packed record riff: array[0..2] of Char; len: DWord; cWavFmt: array[0..7] of Char; dwHdrLen: DWord; wFormat: Word; wNumChannels: Word; dwSampleRate: DWord; | ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 07.12.09. |
23 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
Продолжение Приложения В dwBytesPerSec: DWord; wBlockAlign: Word; wBitsPerSample: Word; cData: array[0..2] of Char; dwDataLen: DWord; end; const BufSize=11000; { Размер буфера на 1 сек}
var Form1: TForm1;
implementation
var WaveIn: hWaveIn; hBuf: THandle; BufHead: TWaveHdr; m: array[1..bufSize] of smallInt; h, w, h2: integer; zs: boolean=false; //запущен звук //Для записи в wav rec: boolean=false; //идет запись mz: array of smallInt; waveHdr: tWaveFileHdr; qz: integer; //записано звука;
{$R *.DFM}
PROCEDURE iniWav; begin WaveHdr.riff: ='RIFF'; WaveHdr.cWavFmt: ='WAVEfmt '; WaveHdr.dwHdrLen: =16; WaveHdr.wFormat: =1; WaveHdr.wNumChannels: =1; WaveHdr.dwSampleRate: =11000; WaveHdr.wBlockAlign: =4; WaveHdr.dwBytesPerSec: =22000; WaveHdr.wBitsPerSample: =16; WaveHdr.cData: ='data'; WaveHdr.dwDataLen: =qz*2; end;
| ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 07.12.09. |
24 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
Продолжение Приложения В procedure TForm1.Button1Click(Sender: TObject); var header: TWaveFormatEx; BufLen: word; buf: pointer;
begin if zs then exit; with header do begin wFormatTag: = WAVE_FORMAT_PCM; nChannels: = 1; // количество каналов nSamplesPerSec: = 11000; // частота wBitsPerSample: = 16; // бит на отсчет nBlockAlign: = nChannels * (wBitsPerSample div 8); nAvgBytesPerSec: = nSamplesPerSec * nBlockAlign; cbSize: = 0; end; WaveInOpen(Addr(WaveIn), WAVE_MAPPER, addr(header), Form1.Handle, 0, CALLBACK_WINDOW); BufLen: = header.nBlockAlign * BufSize; hBuf: = GlobalAlloc(GMEM_MOVEABLE and GMEM_SHARE, BufLen); Buf: = GlobalLock(hBuf); with BufHead do begin lpData: = Buf; dwBufferLength: = BufLen; dwFlags: = WHDR_BEGINLOOP; end; WaveInPrepareHeader(WaveIn, Addr(BufHead), sizeof(BufHead)); WaveInAddBuffer(WaveIn, addr(BufHead), sizeof(BufHead)); zs: =true; WaveInStart(WaveIn); End;
procedure TForm1.Button2Click(Sender: TObject); begin if not zs then Exit; WaveInReset(WaveIn); WaveInUnPrepareHeader(WaveIn, addr(BufHead), sizeof(BufHead)); WaveInClose(WaveIn); GlobalUnlock(hBuf); GlobalFree(hBuf); zs: =false; end; | ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 07.12.09. |
25 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
Продолжение Приложения В
procedure TForm1.OnWaveIn; var data16: PData16; i, d, z, s, x, y, xx, max, s0: integer; begin //сразу пустим запись дальше чтоб не прерывалась WaveInAddBuffer(WaveIn, PWaveHdr(Msg.lParam), SizeOf(TWaveHdr)); data16: = PData16(PWaveHdr(Msg.lParam)^.lpData);
//перепишем звук из массива в который пишется //в массив который обрабатывается чтоб запись его не портила move(data16^[0], m, BufSize*2); if data16^[0]< > m[1] then showMessage('Не успела');
//Обработка звука s: =0; s0: =0; max: =0; for i: = 1 to BufSize do begin z: =m[i]; inc(s0, z); z: =abs(z); inc(s, z); if z> max then max: =z; end;
//показ звука s: =s div bufSize; s0: =s0 div bufSize; label1.caption: ='Среднее: '+intToStr(s)+ ', Максимум: '+intToStr(max)+ ', Постоянный уровень: '+intToStr(s0);
with form1.image1.Picture.Bitmap.canvas do begin fillRect(rect(0, 0, w, h)); pen.color: =$CCCCCC; moveTo(w, h2); lineTo(0, h2); pen.color: =0;
max: =abs(max-abs(s0)); if max< 16 then max: =16; if checkBox1.checked then d: =BufSize else d: =w; for x: =1 to w do begin xx: =x*BufSize div d;
| ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 07.12.09. |
26 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
Продолжение Приложения В y: =h2+(m[xx]-s0)*h2 div max; if x=1 then moveTo(0, y) else lineTo(x, y); end; end; if rec then begin //запись в массив для файла setLength(mz, qz+bufSize+1); move(m[1], mz[qz+1], BufSize*2); inc(qz, BufSize); form1.label2.caption: ='Записано '+formatFloat('0.00', qz*2/1000000)+' мб'; end; end;
procedure TForm1.FormCreate(Sender: TObject); begin w: =image1.width; h: =image1.height; h2: =h div 2; image1.Picture.Bitmap.width: =w; image1.Picture.Bitmap.height: =h; Form1.Button1Click(Sender); end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin Form1.Button2Click(Sender) end;
procedure TForm1.Button2Click(Sender: TObject); begin winExec('SndVol22.exe /r', SW_SHOW); end;
procedure TForm1.BitBtn1Click(Sender: TObject); var fw: file; begin if rec then begin rec: =false; if qz> 0 then begin //вывод в файл wav iniWav; assignFile(fw, 'sound.wav'); rewrite(fw, 1); blockWrite(fw, waveHdr, sizeOf(waveHdr)); | ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 07.12.09. |
27 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
Продолжение Приложения В
blockWrite(fw, mz[1], qz*2); closeFile(fw); showMessage('Записано в " sound.wav" '); label2.visible: =false; BitBtn1.caption: ='Запись'; end; end else begin qz: =0; rec: =true; label2.visible: =true; BitBtn1.caption: ='Стой'; end; end;
end.
const BufSize=11000; { Размер буфера на 1 сек} var Form1: TForm1;
implementation
var WaveIn: hWaveIn; hBuf: THandle; BufHead: TWaveHdr; m: array[1..bufSize] of smallInt; h, w, h2: integer; zs: boolean=false; //запущен звук //Для записи в wav rec: boolean=false; //идет запись mz: array of smallInt; waveHdr: tWaveFileHdr; qz: integer; //записано звука;
{$R *.DFM} PROCEDURE iniWav; begin WaveHdr.riff: ='RIFF'; WaveHdr.cWavFmt: ='WAVEfmt '; WaveHdr.dwHdrLen: =16; WaveHdr.wFormat: =1;
| ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 07.12.09. |
28 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
Продолжение Приложения В
WaveHdr.wNumChannels: =1; WaveHdr.dwSampleRate: =11000; WaveHdr.wBlockAlign: =4; WaveHdr.dwBytesPerSec: =22000; WaveHdr.wBitsPerSample: =16; WaveHdr.cData: ='data'; WaveHdr.dwDataLen: =qz*2; end;
procedure TForm1.Button1Click(Sender: TObject); var header: TWaveFormatEx; BufLen: word; buf: pointer; begin if zs then exit; with header do begin wFormatTag: = WAVE_FORMAT_PCM; nChannels: = 1; // количество каналов nSamplesPerSec: = 11000; // частота wBitsPerSample: = 16; // бит на отсчет nBlockAlign: = nChannels * (wBitsPerSample div 8); nAvgBytesPerSec: = nSamplesPerSec * nBlockAlign; cbSize: = 0; end; WaveInOpen(Addr(WaveIn), WAVE_MAPPER, addr(header), Form1.Handle, 0, CALLBACK_WINDOW); BufLen: = header.nBlockAlign * BufSize; hBuf: = GlobalAlloc(GMEM_MOVEABLE and GMEM_SHARE, BufLen); Buf: = GlobalLock(hBuf); with BufHead do begin lpData: = Buf; dwBufferLength: = BufLen; dwFlags: = WHDR_BEGINLOOP; end; WaveInPrepareHeader(WaveIn, Addr(BufHead), sizeof(BufHead)); WaveInAddBuffer(WaveIn, addr(BufHead), sizeof(BufHead)); zs: =true; WaveInStart(WaveIn); End; procedure TForm1.Button2Click(Sender: TObject); begin if not zs then Exit; | ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 07.12.09. |
29 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
Продолжение приложения В
WaveInReset(WaveIn); WaveInUnPrepareHeader(WaveIn, addr(BufHead), sizeof(BufHead)); WaveInClose(WaveIn); GlobalUnlock(hBuf); GlobalFree(hBuf); zs: =false; end;
procedure TForm1.OnWaveIn; var data16: PData16; i, d, z, s, x, y, xx, max, s0: integer; begin //сразу пустим запись дальше чтоб не прерывалась WaveInAddBuffer(WaveIn, PWaveHdr(Msg.lParam), SizeOf(TWaveHdr)); data16: = PData16(PWaveHdr(Msg.lParam)^.lpData);
//перепишем звук из массива в который пишется //в массив который обрабатывается чтоб запись его не портила move(data16^[0], m, BufSize*2); if data16^[0]< > m[1] then showMessage('Не успела');
//Обработка звука s: =0; s0: =0; max: =0; for i: = 1 to BufSize do begin z: =m[i]; inc(s0, z); z: =abs(z); inc(s, z); if z> max then max: =z; end; //показ звука s: =s div bufSize; s0: =s0 div bufSize; label1.caption: ='Среднее: '+intToStr(s)+ ', Максимум: '+intToStr(max)+ ', Постоянный уровень: '+intToStr(s0); with form1.image1.Picture.Bitmap.canvas do begin fillRect(rect(0, 0, w, h)); pen.color: =$CCCCCC; moveTo(w, h2); lineTo(0, h2); pen.color: =0;
| ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 07.12.09. |
30 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
Продолжение приложения В
max: =abs(max-abs(s0)); if max< 16 then max: =16; if checkBox1.checked then d: =BufSize else d: =w; for x: =1 to w do begin xx: =x*BufSize div d; y: =h2+(m[xx]-s0)*h2 div max; if x=1 then moveTo(0, y) else lineTo(x, y); end; end;
if rec then begin //запись в массив для файла setLength(mz, qz+bufSize+1); move(m[1], mz[qz+1], BufSize*2); inc(qz, BufSize); form1.label2.caption: ='Записано '+formatFloat('0.00', qz*2/1000000)+' мб'; end; end;
procedure TForm1.FormCreate(Sender: TObject); begin w: =image1.width; h: =image1.height; h2: =h div 2; image1.Picture.Bitmap.width: =w; image1.Picture.Bitmap.height: =h; Form1.Button1Click(Sender); end; procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin Form1.Button2Click(Sender) end; procedure TForm1.Button2Click(Sender: TObject); begin winExec('SndVol22.exe /r', SW_SHOW); end; procedure TForm1.BitBtn1Click(Sender: TObject); var fw: file; begin if rec then begin rec: =false;
| ||||||||||||||||||||
Выполнил | Муханов А. | 05.12.09. | КР 3706002 000009 ПЗ | лист | ||||||||||||||||
Проверила | Енсепова Г.К. | 07.12.09. |
31 | |||||||||||||||||
изм | лист | № докум | Подпись | Дата | ||||||||||||||||
Продолжение приложения В
if qz> 0 then begin //вывод в файл wav iniWav; assignFile(fw, 'sound.wav'); rewrite(fw, 1); blockWrite(fw, waveHdr, sizeOf(waveHdr)); blockWrite(fw, mz[1], qz*2); closeFile(fw); showMessage('Записано в " sound.wav" '); label2.visible: =false; BitBtn1.caption: ='Запись'; end; end else begin qz: =0; rec: =true; label2.visible: =true; BitBtn1.caption: ='Стой'; end; end; end. | ||||||||||||||||||||
Выполнил |
Последнее изменение этой страницы: 2020-02-16; Просмотров: 142; Нарушение авторского права страницы