МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ
“ЛЬВІВСЬКА ПОЛІТЕХНІКА”
Кафедра Автоматизовані Системи Управління
Лабораторна робота № 1
з курсу:
Інтерфейси автоматизованих систем обробки
інформації та управління.
на тему:
“Паралельне відтворення декількох звукових файлів
на основі
Media Control Interface”
ТЕОРЕТИЧНІ ВІДОМОСТІ
WAVE-форма звуку виходить при оцифровці, чи дискретизації, безупинної звукової хвилі (англ. wave – хвиля), точніше, аналогового аудіосигналу. При оцифровці спеціальний пристрій – аналого-цифровий перетворювач (АЦП) – вимірює амплітуду хвилі через рівні проміжки часу зі швидкістю кілька тисяч вимірів у секунду і запам'ятовує в Wave-файл обмірювані значення. Вони називаються вибірками (по англ. sample, відкіля ще одна назва дискретизації – сэмплінг).
Зворотне перетворення WAVE-форми звуку в аналоговий сигнал здійснюється цифро-аналоговим перетворювачем (ЦАП).
На мал. 1 показаний фрагмент запису, що містить тільки 50 вибірок
/
Мал. 1. фрагмент запису, що містить тільки 50 вибірок
WAVE-форма цифрового звуку характеризується п'ятьма параметрами:
Частотою дискретизації,
розрядністю вибірок,
числом каналів чи звукових доріжок,
алгоритмом компресії/декомпресії – кодеком,
форматом збереження.
Частота дискретизації
Кількість вибірок в секунду називається частотою дискретизації і виміряється в герцах і кілогерцах (1 кгц=1000 вибірок у сек.). Теоретично, для правильного відновлення аналогового сигналу по його цифровому записі досить, щоб частота дискретизації більш ніж у два рази перевершувала максимальну частоту звуку (теорема Котельнікова-Найквіста). Таким чином, для якісного відтворення найвищого чутного звуку 20 кгц необхідна частота дискретизації не менш 40 кгц. Стандарт CD-DA цифрових аудиодисков вимагає частоти дискретизації 44,1 кгц (так звана CD-якість). Використовуються також частоти 22,05 (радіо-якість) і 11,025 і 8 кгц (телефонна якість), дають у багатьох випадках задовільні результати.
Але при оцифровці звуку дискретизируются і високочастотні гармоніки з частотою, що перевищує половину частоти дискретизації (це високочастотний, нечутний шум). При цьому з'являються нові небажані гармоніки з чутного діапазону (низькочастотний шум, див. мал. 2).
/
Мал. 4. Низькочастотний шум
Тому для одержання якісного цифрового звуку процес дискретизації будується за наступною схемою [Симаненков]:
часткове придушення високочастотних перешкод в аналоговому сигналі за допомогою аналогового фільтра;
оверсемплінг – дискретизація з частотою, що значно перевищує необхідну (при цьому шум, що утвориться, лежить все ще в нечутному діапазоні);
придушення високочастотного шуму в цифровому звуці за допомогою цифрового фільтра;
перетворення до необхідної частоти дискретизації.
Оверсемплінг застосовується і при зворотному перетворенні в аналоговий сигнал. При цьому використовуються різні методи лінійної і нелінійної інтерполяції [Симаненков].
Компресія звуку
Позначимо
W – обсяг пам'яті в байтах для збереження 1 секунди звуку в WAVE-формі,
w – швидкість потоку звукових даних у WAVE-формі в біт/сек,
H – частоту дискретизації (число вибірок у секунду),
B – розрядність квантування (число розрядів на вибірку),
C – число каналів.
Тоді очевидно, що w = HBC і, якщо B кратне 8, W = w/8. Отже,
швидкість потоку дані CD-якості (H=44100, B=16, C=2) складає 1 411 200 біт/сек чи 1378,125 Кбіт/сек (така швидкість забезпечується тільки CD-дисководом з не менш, ніж 2-кратною швидкістю),
1 година звуку з якістю CD-DA зажадає 605,6 Мбайт (тому на аудіодиску міститься близько 70 хвилин незтиснутого звуку),
швидкість потоку даних телефонної якості (H=8000, B=8, C=1) складає 64 000 біт/сек чи 62,5 Кбіт/сек (така швидкість забезпечується далеко не кожним модемом, так що такий звук не може використовуватися в Інтернет-телефонії).
З метою зменшення обсягу і потоку звукових даних у WAVE-формі використовуються різні спеціальні алгоритми компресії/декомпресії (кодеки), тому що звичайні алгоритми стиску інформації тут не дають ефекту. Стиск аудіоданих можливо лише з деякою втратою інформації, але облік психофізіологічних особливостей сприйняття звуку (наприклад, не всі частоти в чутному діапазоні істотні для сприйняття), дозволяє в ряді випадків зробити ці втрати практично непомітними. Випливає, однак, враховувати дуже високу чутливість людського слухового апарата, особливо до тимчасових характеристик звуку. Найбільш відомими є наступні кодеки, використовувані в мультимедіа під Windows:
PCM (Pulse Code Modulation) – імпульсно-кодова модуляція (ІКМ) – стиск може досягатися тільки за рахунок вибору менших значень величин H, B і C (фактично, це незтиснутий звук); квантування відбувається по рівномірній шкалі з 2B значень;
DPCM (Differential PCM) – диференціальна ІКМ (ДІКМ)– вибірка представляється своєю різницею від попередньої, що вимагає менше B бітів; стискає в кілька разів;
ADPCM (Adaptive DPCM) – адаптивна ДІКМ (АДІКМ) – те ж, що ДІКМ, тільки квантування відбувається не по рівномірній шкалі, а з врахуванням динаміки змін амплітуди; стискає в кілька разів;
MPEG (Motion Picture Experts Group) – стандарти Групи експертів в області кіно; для стиску звукової інформації використовуються стандарти MP2 і MP3; застосовується психоакустична компресія, при якій віддаляються звуки, не сприймані людським вухом; стискає в кілька десятків разів при досить високій якості;
RealAudio – метод, розроблений фірмою RealNetworks, стискає в кілька десятків разів, але з невисокою якістю; використовується в Інтернету для програвання звукових файлів у реальному часі.
Формати WAVE-файлів
Часто кодек визначає і формат аудиофайла, і, відповідно, його розширення:
MPEG – ".mpa", ".mp3",
RealAudio – ".ra", ".rm".
Більш гнучким є WAV-формат для Windows (файли з розширенням ".wav"). В його основі лежить формат RIFF (Resourse Interchange File Format), що дозволяє зберігати довільні дані в структурованому виді. Для запису звуку в цьому форматі можуть бути використані різні кодеки.
У форматі RIFF файли поділяються на блоки даних (Chunks), що містять число байтів, кратне 4. Кожен блок починається з 4-байтового ідентифікатора, за яким випливає 4 байти з довжиною блоку чи файлу. При необхідності блок доповнюється нульовими байтами, але розмір вказується без обліку цих байтів.
WAV-файл складається з трьох блоків – двох заголовних і одного блоку звукових даних. Перший блок має ідентифікатор "RIFF", за яким у 4-х байтах випливає розмір файлу (без обліку перших 8 байтів). В наступних 4-х байтах лежить ідентифікатор "WAVE", що вказує тип RIFF-файлу.
Наступний заголовний блок містить байти в наступному порядку:
4 байти – ідентифікатор "fmt_"4 байти – число 16 (розмір даних блоку)2 байти – інформація про кодек (1 для PCM)2 байти – число каналів (1 – моно, 2 – стерео)4 байти – частота дискретизації (при 44100 Гц – AC44H)4 байти – число байтів в секунду, рівне W, якщо B кратно 82 байти – число байтів на один відлік, рівне BC/8, якщо B кратно 82 байти – число бітів на вибірку B (якщо B не кратне 8, то вибірки доповнюються нулями до цілого числа байтів).
Останній блок – дані відліків – починається ідентифікатором "data", за яким розташовані 4 байти – розмір блоку, а потім самі дані. У випадку стереовідліку дані для обох каналів розташовуються друг за другом: спочатку вибірка для лівого каналу, потім вибірка для правого, і т.д.
Керування мультимедіа за допомогою MCI – Media Control Interface
При створенні мультимедійних програм в якій-небудь системі програмування для роботи з мультимедіа можна використовувати спеціальні бібліотеки функцій як дуже високого рівня (наприклад, "PlaySound ім'я файлу"), так і дуже низького рівня (наприклад, "вибрати блок даних з Wav-файлу")
У Windows, починаючи з версії 3.1, визначений деякий проміжний рівень керування мультимедійними даними і пристроями – MCI (Media Control Interface – інтерфейс керування мультимедіа). Він включає набір команд, що посилаються драйверам пристроїв. У MCI під пристроєм розуміється драйвер, фізичний мультимедіа-пристрій і/чи файл, якими керує цей драйвер. MCI-пристрій, що не використовує мультимедіа-файли, називаються простими, а інші – складними.
Використання MCI-команд у програмах
Програми, що використовують MCI, посилають драйверам команди за допомогою функцій mciSendString і mciSendCommand зі стандартної бібліотеки Mmsystem.dll (папка Windows\System). Перша з них посилає команду у виді текстового рядка, а друга – у виді стандартних констант і структур даних, що попередньо потрібно заповнити. Через більшу простоту розглянемо тільки перший спосіб.
Прототип функції mciSendString мовою С має вид:
DWORD mciSendString(LPSTR lpstrCmd, LPSTR lpstrRetStr,UINT wRetLength, HWND hwndCallback)
Перший параметр обов'язковий – це сам командний рядок. Інші необов'язкові. Вони визначають буфер, куди посилається відповідь, його довжину і вікно для посилки повідомлення (notify) програмі від пристрою. Сама функція при успішному виконанні команди повертає 0, а у випадку помилки – негативне значення. Це значення можна передати як перший параметр функції mciGetErrorString (з тієї ж бібліотеки Mmsystem.dll) – функція поверне текстовий опис помилки:
UINT mciGetErrorString(DWORD dwError, LPSTR lpstrBuffer,UINT wLength)
Для уточнення подробиць потрібно в вибрати посилання Function Overview, потім посилання Media Control Interface services і, нарешті, посилання Communicating with MCI Devices.
Але не тільки в мові С можна використовувати команди MCI. Нижче ми будемо розглядати авторскі системи, в яких також використовуються ці команди. Вони дозволяють дуже гнучко керувати відтворенням і записом мультимедійних даних. Наприклад, в системі Toolbook для цього використовується функція callMCI.
Робота програми з пристроєм починається з його відкриття командою open і закінчується закриттям командою close. Незакритий пристрій не може бути відкрито ще раз, якщо воно не було оголошено обома командами open як поділюване (shareable). Приведемо приклади послідовностей MCI-команд в основному командному потоці.
Програвання CD-Audio:
open cdaudio ...
set cdaudio time format tmsf ... -і tmsf - доріжка:хвилина:секунда:кадр
play cdaudio from 1:00:00 to 3:00:00 wait... -і грати доріжки з 1 по 3
pause cdaudio
close cdaudio
-- для CD-Audio тільки pause припиняє програвання.
Програвання MIDI-файлу:
open c:\windows\media\Passport.mid type sequencer alias s...
set s time format ms -і ms - мілісекунда...
play s from 0 to 10000 wait -і грати перші 10 секунд...
close s
Програвання Wav-файлу:
open c:\windows\media\Tada.wav type waveaudio alias s...
play s from 0 ... - чекання події, що означає "кінець програвання"
close s
Запис Wav-файлу:
open new type waveaudio alias s...
record s ... -і чекання події, що означає "кінець запису"
save s c:\windows\temp\haha.wav
close s
Синтаксис командного рядка MCI
Командний рядок має вигляд:
команда покажчика-пристрою, де параметри: команда – це назва команди, наприклад open, play, close; покажчика-пристрою – це
тип пристрою – для будь-якої команди простого пристрою, наприклад cdaudio
шлях і ім'я файлу в команді для складного пристрою, наприклад c:\windows\media\Tada.wav; у будь-якій команді, крім open може бути замінений псевдонімом (це, як правило, і відбувається)
псевдонім, встановлений параметром alias попередньої команди open, наприклад s
слово new у команді open при відкритті пристрою на запис звуку чи відео
слово all – для посилки команди усім відкритим у даній програмі пристроям (можна застосовувати тільки до команд, що не повертають інформацію), наприклад, close all.
параметри – це (можливо порожня) послідовність параметрів, розділених пробілом, у якій кожен параметр – це непорожня послідовність ключових слів і значень, розділених пробілами, наприклад, time format tmsf, чи type waveaudio, чи from 0, чи c:\windows\temp\haha.wav у команді save.
Параметри записуються в довільному порядку, можуть бути обов'язковими і необов'язковими. Їхній набір визначається командою, але два параметри є загальними для всіх команд (і необов'язковими) – це wait і notify.
Використання параметра wait
Більшість MCI-команд запускає новий процес, у якому бере участь MCI-пристрій, наприклад, процес програвання доріжки аудіодиска. Якщо в команді використовується параметр wait, то команда чекає закінчення цього процесу, а потім передає керування далі по програмі. Достроково продовжити виконання програми (без припинення MCI-процесу, тобто паралельно з ним) у цьому випадку можна тільки натисканням клавіші переривання CTRL+BREAK. За допомогою MCI-команди break можна змінити цю чи клавішу навіть зовсім скасувати можливість продовження програми до закінчення MCI-процесу.
Якщо ж у MCI-команді відсутній параметр wait, то вона не чекає закінчення створеного нею MCI-процесу, а відразу передає керування далі по програмі, тобто новий MCI-процес виконується паралельно з основною програмою. Так легко можна озвучити будь-який програмний фрагмент. У цьому випадку, як правило, у програмі передбачається дострокове припинення MCI-процесу за допомогою іншої MCI-команди (наприклад, close, pause чи навіть знову play), викликуваної якою-небудь подією, наприклад, кліком миші. Іноді програмі необхідно ловити момент завершення рівнобіжного MCI-процесу. Для цього в MCI-команді, що запускає процес, notify.
Використання параметра notify
MCI-команда, запустивши відповідний MCI-процес, може передати керування основній програмі, після чого програма і цей процес будуть виконуватися паралельно. Щоб програма могла довідатися про завершення рівнобіжного MCI-процесу, не перевіряючи цього самостійно (що дуже важко), можна в MCI-команді, що запускає процес, використовувати параметр notify. Це змушує MCI-пристрій у випадку завершення процесу послати повідомлення MM_MCINOTIFY, що інформує про характер завершення і пристрій.
Повідомлення автоматично направляється вікну, зазначеному четвертим параметром функції mciSendString, яка послала команду з параметром notify, і може бути оброблено процедурою цього вікна.
Мова, на якій пишеться ця процедура, повинна одержувати це повідомлення своїми засобами, тому що MCI такої можливості не надає. Процедура, відреагувавши на повідомлення MM_MCINOTIFY, може знову послати ту чи іншу MCI-команду, наприклад, закрити пристрій, що закінчив програвання.
Команди MCI
Команди MCI поділяються на:
системні, виконувані не MCI-пристроями, а самою системою;
обов’язкові для всіх MCI-пристроїв;
основні, які представляють загальний набір параметрів для тих MCI-пристроїв, на яких вони виконуються;
розширені, набір і параметри яких визначаються пристроєм.
Списки системних, обов'язкових і основних команд і їхніх параметрів приводяться нижче. Більш докладна інформація про їх, а також про розширені команди по кожному з основних типів пристроїв приведена в довіднику MCI Command Strings.
Системні команди
Системні команди не передаються MCI-пристроям, а обробляються самою системою MCI.
break - Встановлює клавішу переривання для MCI-пристрою
{off | on код клавіші}
Sysinfo - Повертає інформацію про MCI-пристрої {installname | name індекс | name індекс open | quantity | quantity open}
Обов'язкові команди
Обов'язкові команди разом з перерахованими тут параметрами повинні підтримуватися всіма MCI-пристроями. Кожен пристрій може підтримувати додаткові параметри цих команд.
Capability- Повідомляє про можливості пристрою{can eject | can play | can record | can save | compound device | device type | has audio | has video | uses files}
Close - Закриває пристрій
Info - Одержує текстову інформацію від пристрою [product]
Open - Відкриває пристрій [alias псевдонім] [shareable] [type тип пристрою]
Status – Інформує про стан пристрою[mode | ready] У випадку параметра mode обов'язковим набором відповідей є not ready | paused | playing | stopped
Основні команди
Основні команди можуть підтримуватися не всіма пристроями. Але якщо деякий драйвер підтримує основну команду, то він повинен підтримувати і всі перераховані тут її параметри.
Load - Завантажує дані з файлу {ім'я файлу}
Pause - Припиняє чи запис програвання
Play - Починає програвання [from позиция] [to позиция]
Record - Починає запис [from позиция] [to позиция] [insert | overwrite]
Resume - Відновляє припинений чи запис програвання
Save - Зберігає дані у файл[ім'я файлу]
Seek - "Перемотування" вперед чи назад {to позиция| to start | to end}
Set - Встановлює режими пристрою [audio all off | audio all on | audio left off | audio left on | audio right off | audio right on | video off | video on] [door closed | door open] [time format milliseconds | time format ms]
Status - Інформує про стан пристрою {current track | length | length track номер | mode | number of tracks | position | position track номер | ready | start position | time format}
Stop - Зупиняє чи запис програвання
Зауваження. Тут до обов'язкової команди status додані параметри, актуальні для лінійних мультимедіа-даних з можливістю вказівки позиції. Позиція вказується в одному з наступних форматів:
Milliseconds (ms) – Мілісекунда
Msf - хвилина:секунда:кадр
Tmsf - доріжка:хвилина:секунда:кадр
Hms - година:хвилина:секунда (для відеодиска)
Bytes - байт (для waveaudio)
Samples - вибірка (для waveaudio)
Frames – Кадр
Track - доріжка (для відеодиска)
Song pointer - 1/16 ноти (для MIDI у форматі PPQN)
Smpte 24, 25, 30, 30 drop - для MIDI у форматах PPQN і SMPTE
Керівництво користувачу
Запускаємо файл PSPlayer.exe. На екрані з’явиться вікно програми “Parrallel wave file player” (мал.1).
Мал.1 Головне вікно програми
Виберіть за допомогою Select File один чи декілька звукових файлів у форматі WAVE. Для того, щоб прослухати wave-файл натисніть кнопку ((Play). Після того, як ми натиснули на кнопку ((Play), значок автоматично заміниться на ((Stop). Для того, щоб зробити паузу підчас програвання файлу потрібно натиснути ((Pause). Переміщатись по пісні можна за допомогою Progressbar’у, який зафарбовується з часом кольором (для того, щоб в будь-який момент часу переміститися по звуковому файлі, досить клікнути по Progressbar’у лівою кнопкою миші). Велика кнопка ((Play) запустить на програвання одразу всі заантажені звукові файли.
Висновки
В даній лабораторній роботі я створив в середовищі Borland C++ Builder програму, яка може паралельно відтворювати звукові файли у форматі WAVE,
я використав об’єктно-орієнтований підхід для вирішення поставленої задачі, який дозволив спростити використання складного механізму відтворення звукових файлів формату WAVE до мінімуму.
Додаток: лістинг програми на мові С++ в середовищі Borland C++ Builder.
File MCIWaveFile.h :
class MCIWaveFile
{
private:
bool state;
DWORD dwError;
String szErrorBuf;
MCIERROR dwReturn;
MCIDEVICEID wDeviceID;
DWORD Length;
MCI_STATUS_PARMS mciStatusParam;
MCI_SEEK_PARMS mciSeekParam;
MCI_PLAY_PARMS mciPlayParam;
MCI_GENERIC_PARMS mciGenParam;
MCI_OPEN_PARMS mciOpenParam;
MCI_SET_PARMS mciSetParam;
public:
MCIWaveFile(char* FileName);
void ShowError();
DWORD GetLength();
DWORD GetFilePosition();
DWORD SetFilePosition(DWORD Value);
void DoPause();
void DoResume();
void PlaySound();
bool GetDeviceState(void) { return state;};
virtual ~MCIWaveFile();
};
File MCIWaveFile.cpp :
MCIWaveFile::MCIWaveFile(char* FileName){
mciOpenParam.lpstrDeviceType="WaveAudio";
mciOpenParam.lpstrElementName=FileName;
dwReturn=mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD)&mciOpenParam);
if (dwReturn!=0) ShowError();
state=true;
wDeviceID=mciOpenParam.wDeviceID;
Length=GetLength();
mciPlayParam.dwCallback=(DWORD)Form1->Handle;
};
void MCIWaveFile::PlaySound(){
dwReturn=mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY, DWORD(&mciPlayParam));
if (dwReturn!=0){
mciSendCommand(wDeviceID, MCI_CLOSE, 0, DWORD(&mciGenParam));
ShowError();
state=false;
};
};
void MCIWaveFile::ShowError(){
if (mciGetErrorString(dwError, szErrorBuf.c_str(), MAX_PATH))
MessageBox(Form1->Handle, szErrorBuf.c_str(), "MCI Error", MB_ICONEXCLAMATION);
else
MessageBox(Form1->Handle, "Unknown Error", "MCI Error", MB_ICONEXCLAMATION);
};
DWORD MCIWaveFile::GetLength(){
if (state) {
mciStatusParam.dwItem=MCI_STATUS_LENGTH;
wDeviceID=mciOpenParam.wDeviceID;
dwReturn=mciSendCommand(wDeviceID, MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM, DWORD(&mciStatusParam));
if (dwReturn!=0) {
ShowError();
mciSendCommand(wDeviceID, MCI_CLOSE, 0, DWORD(&mciGenParam));
}
else{
return mciStatusParam.dwReturn;
}
}
else ShowMessage("Device Is Not Opened !");
};
DWORD MCIWaveFile::GetFilePosition(){
if (state) {
mciStatusParam.dwItem=MCI_STATUS_POSITION | MCI_FORMAT_MILLISECONDS;
dwReturn=mciSendCommand(wDeviceID, MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM, DWORD(&mciStatusParam));
if (dwReturn!=0) {
ShowError();
mciSendCommand(wDeviceID, MCI_CLOSE, 0, DWORD(&mciGenParam));
}
else return mciStatusParam.dwReturn;
}
else ShowMessage("Device Is Not Opened !");
};
DWORD MCIWaveFile::SetFilePosition(DWORD Value) {
if (state){
mciSeekParam.dwCallback=(DWORD)Form1->Handle;
mciSeekParam.dwTo=Value;
dwReturn= mciSendCommand(wDeviceID, MCI_SEEK, MCI_WAIT | MCI_TO, DWORD(&mciSeekParam));
if (dwReturn!=0) {
ShowError();
mciSendCommand(wDeviceID, MCI_CLOSE, 0, DWORD(&mciGenParam));
}
mciPlayParam.dwCallback=(DWORD)Form1->Handle;
dwReturn=mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY, DWORD(&mciPlayParam));
if (dwReturn!=0){
mciSendCommand(wDeviceID, MCI_CLOSE, 0, DWORD(&mciGenParam));
ShowError();
state=false;
};
}
else ShowMessage("Device Is Not Opened !");
};
void MCIWaveFile::DoPause(){
if (state) {
mciGenParam.dwCallback=(DWORD)Form1->Handle;
dwReturn=mciSendCommand(wDeviceID, MCI_PAUSE, MCI_WAIT, DWORD(&mciGenParam));
if (dwReturn!=0){
ShowError();
mciSendCommand(wDeviceID, MCI_CLOSE, 0, DWORD(&mciGenParam));
}
}
else ShowMessage("Device Is Not Opened !");
};
void MCIWaveFile::DoResume(){
if (state){
mciGenParam.dwCallback=(DWORD)Form1->Handle;
dwReturn=mciSendCommand(wDeviceID, MCI_RESUME, MCI_WAIT, DWORD(&mciGenParam));
if (dwReturn!=0){
ShowError();
mciSendCommand(wDeviceID, MCI_CLOSE, 0, DWORD(&mciGenParam));
};
}
else ShowMessage("Device Is Not Opened !");
};
MCIWaveFile::~MCIWaveFile(){
if (state) mciSendCommand(wDeviceID, MCI_CLOSE, 0, DWORD(&mciGenParam));
};
File Player.cpp :
#include <vcl.h>
#pragma hdrstop
#include "Player.h"
#include "MCIWaveFile.h"
#include "MCIWaveFile.cpp"
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
MCIWaveFile *pwf1=0;
MCIWaveFile *pwf2=0;
MCIWaveFile *pwf3=0;
void __fastcall TForm1::Play1BtnClick(TObject *Sender)
{
if ( !(StrLen(Label1->Caption.c_str())) )
ShowMessage("Please select file to play!");
else
{
if (Play1Btn->Caption=="4")
{
pwf1=new MCIWaveFile(Label1->Caption.c_str());
pwf1->PlaySoundA();
Timer1->Enabled=true;
Play1Btn->Caption="<";
ProgressBar1->Max=pwf1->GetLength();
ProgressBar1->Min=0;
}
else
{
Timer1->Enabled=false;
Play1Btn->Caption="4";
delete pwf1;
pwf1=NULL;
};
};
}
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
long l;
if (pwf1->GetDeviceState())
{
ProgressBar1->Position=pwf1->GetFilePosition();
l=ProgressBar1->Position/1000;
Panel1->Caption=IntToStr(l / 3600)+ ':'+IntToStr(l / 60)+':'+IntToStr(l-((l / 60)*60));
l=pwf1->GetLength() / 1000;
Panel1->Caption=Panel1->Caption+" / "+IntToStr(l / 3600)+':'+IntToStr(l / 60)+':'+IntToStr(l-((l / 60)*60));
if (pwf1->GetFilePosition()==pwf1->GetLength())
{
pwf1->SetFilePosition(0);
ProgressBar1->Position=0;
Play1Btn->Caption="4";
Timer1->Enabled=false;
delete pwf1;
pwf1=NULL;
};
};
}
void __fastcall TForm1::ProgressBar1MouseUp(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
DWORD pos;
if (pwf1!=NULL)
{
if (pwf1->GetDeviceState())
{
pos=pwf1->GetLength()/ProgressBar1->Width*X;
ProgressBar1->Position=pos;
pwf1->SetFilePosition(pos);
}
else ProgressBar1->Position=0;
};
}
void __fastcall TForm1::Pause1BtnClick(TObject *Sender)
{
if (pwf1!=NULL)
{
if (Pause1Btn->Caption==";")
{
Pause1Btn->Caption="4";
pwf1->DoPause();
}
else
{
Pause1Btn->Caption=";";
pwf1->DoResume();
};
};
}
void __fastcall TForm1::SelectFile1BtnClick(TObject *Sender)
{
if (OpenDialog1->Execute()) Label1->Caption=OpenDialog1->FileName;
}
void __fastcall TForm1::SelectFile2BtnClick(TObject *Sender)
{
if (OpenDialog1->Execute()) Label2->Caption=OpenDialog1->FileName;
}
void __fastcall TForm1::SelectFile3BtnClick(TObject *Sender)
{
if (OpenDialog1->Execute()) Label3->Caption=OpenDialog1->FileName;
}
void __fastcall TForm1::Play2BtnClick(TObject *Sender)
{
if ( !(StrLen(Label2->Caption.c_str())) )
ShowMessage("Please select file to play!");
else
{
if (Play2Btn->Caption=="4")
{
pwf2=new MCIWaveFile(Label2->Caption.c_str());
pwf2->PlaySoundA();
Timer2->Enabled=true;
Play2Btn->Caption="<";
ProgressBar2->Max=pwf2->GetLength();
ProgressBar2->Min=0;
}
else
{
Timer2->Enabled=false;
Play2Btn->Caption="4";
delete pwf2;
pwf2=NULL;
};
};
}
void __fastcall TForm1::Play3BtnClick(TObject *Sender)
{
if ( !(StrLen(Label3->Caption.c_str())) )
ShowMessage("Please select file to play!");
else
{
if (Play3Btn->Caption=="4")
{
pwf3=new MCIWaveFile(Label3->Caption.c_str());
pwf3->PlaySoundA();
Timer3->Enabled=true;
Play3Btn->Caption="<";
ProgressBar3->Max=pwf3->GetLength();
ProgressBar3->Min=0;
}
else
{
Timer3->Enabled=false;
Play3Btn->Caption="4";
delete pwf3;
pwf3=NULL;
};
};
}
void __fastcall TForm1::Pause2BtnClick(TObject *Sender)
{
if (pwf2!=NULL)
{
if (Pause2Btn->Caption==";")
{
Pause2Btn->Caption="4";
pwf2->DoPause();
}
else
{
Pause2Btn->Caption=";";
pwf2->DoResume();
};
};
}
void __fastcall TForm1::Pause3BtnClick(TObject *Sender)
{
if (pwf3!=NULL)
{
if (Pause3Btn->Caption==";")
{
Pause3Btn->Caption="4";
pwf3->DoPause();
}
else
{
Pause3Btn->Caption=";";
pwf3->DoResume();
};
};
}
void __fastcall TForm1::Timer2Timer(TObject *Sender)
{
long l;
if (pwf2->GetDeviceState())
{
ProgressBar2->Position=pwf2->GetFilePosition();
l=ProgressBar2->Position/1000;
Panel2->Caption=IntToStr(l / 3600)+ ':'+IntToStr(l / 60)+':'+IntToStr(l-((l / 60)*60));
l=pwf2->GetLength() / 1000;
Panel2->Caption=Panel2->Caption+" / "+IntToStr(l / 3600)+':'+IntToStr(l / 60)+':'+IntToStr(l-((l / 60)*60));
if (pwf2->GetFilePosition()==pwf2->GetLength())
{
pwf2->SetFilePosition(0);
ProgressBar2->Position=0;
Play2Btn->Caption="4";
Timer2->Enabled=false;
delete pwf2;
pwf2=NULL;
};
};
}
void __fastcall TForm1::Timer3Timer(TObject *Sender)
{
long l;
if (pwf3->GetDeviceState())
{
ProgressBar3->Position=pwf3->GetFilePosition();
l=ProgressBar3->Position/1000;
Panel3->Caption=IntToStr(l / 3600)+ ':'+IntToStr(l / 60)+':'+IntToStr(l-((l / 60)*60));
l=pwf3->GetLength() / 1000;
Panel3->Caption=Panel3->Caption+" / "+IntToStr(l / 3600)+':'+IntToStr(l / 60)+':'+IntToStr(l-((l / 60)*60));
if (pwf3->GetFilePosition()==pwf3->GetLength())
{
pwf3->SetFilePosition(0);
ProgressBar3->Position=0;
Play3Btn->Caption="4";
Timer3->Enabled=false;
delete pwf3;
pwf3=NULL;
};
};
}
void __fastcall TForm1::GlobalPlayBtnClick(TObject *Sender)
{
if (GlobalPlayBtn->Caption!="<")
{
GlobalPlayBtn->Caption="<";
Play1Btn->Click();
Play2Btn->Click();
Play3Btn->Click();
}
else
{
GlobalPlayBtn->Caption="4";
Play1Btn->Click();
Play2Btn->Click();
Play3Btn->Click();
}
}
void __fastcall TForm1::ProgressBar2MouseUp(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
DWORD pos;
if (pwf2!=NULL)
{
if (pwf2->GetDeviceState())
{
pos=pwf2->GetLength()/ProgressBar2->Width*X;
ProgressBar2->Position=pos;
pwf2->SetFilePosition(pos);
}
else ProgressBar2->Position=0;
};
}
void __fastcall TForm1::ProgressBar3MouseUp(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
DWORD pos;
if (pwf3!=NULL)
{
if (pwf3->GetDeviceState())
{
pos=pwf3->GetLength()/ProgressBar3->Width*X