Таймер и музыка через порты спикера для ОС Unix/Linux/FreeBSD .. на C++,CPP,Си


Добавил:DMT
Дата создания:5 апреля 2008, 22:55
Дата обновления:5 апреля 2008, 22:57
Просмотров:8834 последний 26 сентября, 5:24
Комментариев: 0
Таймер и музыка
Когда-то давно, учась в университете нам дали задание - заставить спикер пищать под Unix. Не большое количество человек справились с этим заданием. Вообще работа с портами, что под Windows, что под Unix - практически одинакава, но в Unixовых есть такая заморочка - необходимо открыть доступ к используемым портам, в Windows порты спикера открыты, в здесь нет, да и открыть лоступ можно только под правами админа. Я, DMT накатал исходник и делюсь им с Вами, вдруг кому пригодится. Да и всем делюсь!!! Смотрите все исходники!!! :))
Надо было же, я искал - что же мне на спикере то проиграть!?? Не мог же я - при своих навыках ))) смеюсь - придти к преподавателю и запустить какой-нибудь сташный звук, типа: бип бип брр хрр. Не я хотел большего!!! :) Расковырял несколько досовских(DOS) игр - поиграв в них сперва - оценив звуки, потом проанализировал код одной - понравившейся, нашел данные за кодом в непонятном формате. Разобрал логику и накатал прогу на pascale для выгрузки этой мелодии!! )) глупо )) но мелодию писать самому мне не хотелось ). Вот и получился прошлый гимн нашей РОДИНЫ. Я патриот - поэтому считаю его совершенством.
Далее Общее вступления для того, чтобы Вы нашли исходник и сам исходник.
Одно из наиболее распространенных применений таймера - генерация звуковых сигналов и воспроизведение музыки. Таймер позволяет воспроизводить музыку в фоновом режиме, т. е. во время работы программы может звучать музыка (в самом простом виде ее воспроизведения).
Как мы уже говорили, канал 2 микросхемы 8254 связан с гро-мкоговорителем компьютера. Однако громкоговоритель не просто соединен с выходом OUT канала 2. Порт вывода 6Ih также ис-пользуется для управления громкоговорителем. Младший бит по-рта 61h подключен ко входу GATE канала 2 таймера. Этот бит при установке в 1 разрешает работу канала, т. е. генерацию им-пульсов для громкоговорителя.
Дополнительно для управления громкоговорителем используется бит 1 порта 61h. Если этот бит установлен в 1, импульсы от канала 2 таймера смогут проходить на громкоговоритель.
Таким образом, для включения звука надо выполнить следую-щие действия:
запрограммировать канал 2 таймера на нужную частоту (т. е. загрузить регистр счетчика канала нужным значе-нием) ;
для включения звука установить в 1 два младших бита порта 61h.
Так как остальные б битов порта 61h используются для других целей, установка младших битов должна выполняться таким об-разом, чтобы значения остальных битов не были изменены. Для этого вначале надо считать байт из порта 61h в рабочую ячейку памяти, установить там нужные биты, затем вывести новое зна-чение байта в порт 61h.
Очевидно, что для выключения звука надо сбросить два млад-ших бита порта 61h в 0 (при этом нельзя изменять значение ос-тальных битов этого порта).
Мелодия (одноголосая), как известно, состоит из нот, разде-ленных или не разделенных паузами. При проигрывании мелодии необходимо для каждой ноты программировать соответствующим образом канал 2 таймера и включать громкоговоритель (с помо-щью порта 61h) на определенное время, равное длительности ноты. Затем программа должна выключить динамик и выдержать паузу, если требуется, перед проигрыванием следующей ноты.
Программа может генерировать звуки и другим способом, не используя таймер. Для этого нужно сбросить младший бит порта 61h и, управляя битом 1 этого порта, формировать импульсы для громкоговорителя, т. е. программа должна устанавливать этот бит то в 0, то в 1 с некоторым периодом. Высота генерируемого звука будет соответствовать этому периоду.
Можно также комбинировать эти два способа, получая разно-образные звуковые эффекты.
Для проигрывания мелодии в фоновом режиме можно предло-жить следующий способ, основанный на использовании периоди-ческого прерывания от канала 0 таймера.
Основная идея заключается в использовании прерывания 1Ch, которое вырабатывается таймером с частотой примерно 18,2 Гц. Ваш обработчик этого прерывания осуществляет контроль за вы-боркой нот из массива, содержащего мелодию, и программирова-ние микросхемы 8254. Например, один раз в полсекунды обработ-чик проверяет, не пора ли прекратить звучание одной ноты и на-чать проигрывание следующей ноты. Если пора, он выключает громкоговоритель и перепрограммирует канал 8254 на новую час-тоту, соответствующую следующей ноте.
Основное преимущество использования таймера для проигры-вания мелодии - независимость констант, используемых для программирования канала таймера от производительности системы. Ва-ша мелодия будет звучать одинаково и на медленной IBM XT, и на Super - AT с процессором 80486, но при условии, что Вы будете использовать таймер и для организации задержек при исполнении мелодии.
Для определения значения, которое должно быть записано в регистр счетчика канала 2 таймера, надо разделить 1193180 на требуемую частоту в герцах.
В таблице ниже приведены частоты нот для второй октавы. При повышении (понижении) тона на октаву частота соответствующей ноты умножается (делится) на два.
Нота Частота, Гц
До 261,7
До-диез 277,2
Ре 293,7
Ре-диез 311,1
Ми 329,6
Фа 349,2
Фа-диез 370,0
Соль 392,0
Соль-диез 415,3
Ля 440,0
Ля-диез 466,2
Си 493,9

Текст программы
Код на C++
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <asm/io.h>
  4. #include <fcntl.h>
  5.  
  6. void sound(int freq){
  7. char b;
  8. if (freq>18){
  9. freq=(int)(1193181/freq);
  10. b=inb(0x61);
  11. printf("Get port 0x61=%d\n",b);
  12. printf(" b&3=%d\n",b&3);
  13. printf(" b|3=%d\n",b|3);
  14. outb(b|3,0x61);
  15. outb(0xB6,0x43);
  16. printf(" freq = %d\n",freq);
  17. printf(" freq low = %d\n",freq>>8);
  18. outb(freq,0x42);
  19. outb(freq>>8,0x42);
  20. }
  21. }
  22.  
  23. void nosond(){
  24. char b;
  25. b=inb(0x61);
  26. b&=0xFC;
  27. outb(b,0x61);
  28. }
  29.  
  30. int main(void){
  31. int atn[98]={196,262,196,220,247,165,165,220,196,175,196,131,131,
  32. 147,147,165,175,175,196,220,247,262,294,196,330,294,262,294,247,
  33. 196,262,247,220,247,165,165,220,196,175,196,131,131,262,247,220,
  34. 196,330,294,262,247,262,294,196,196,262,247,220,196,220,247,165,
  35. 165,262,220,247,262,220,247,262,220,262,350,350,330,294,262,294,
  36. 330,262,262,294,262,247,220,247,262,220,220,262,247,220,196,131,
  37. 131,196,220,246,262};
  38. int adr[98]={400,800,600,200,800,400,400,800,600,200,800,
  39. 400,400,800,400,400,800,400,400,800,400,400,1200,400,
  40. 800,600,200,800,400,400,800,600,200,800,400,400,800,
  41. 400,400,800,400,400,800,400,400,1600,1600,400,400,400,
  42. 400,1200,400,1600,1600,400,400,400,400,1200,400,1600,
  43. 800,600,200,800,600,200,800,400,400,1600,1600,400,400,
  44. 400,400,1200,400,1600,1600,400,400,400,400,1200,400,
  45. 1600,800,400,400,800,600,200,1600,800,800,3200};
  46. int sp,dr,tn;
  47. dr=1000;
  48. tn=1000;
  49. printf("Test beepper\n");
  50. if (ioperm(0x40,0x40,1)){
  51. printf("Error. You havn't right.\nExit (1)\n");
  52. exit(1);
  53. }
  54.  
  55. int i;
  56. for (i=0;i<98;i++){
  57. sound(atn[i]);
  58. usleep(adr[i]*400);
  59. // попробуйте изменить время проигрывания
  60. // ноты поменяв множитель 400 на другое число
  61. }
  62. nosond();
  63. if (ioperm(0x40,0x40,0)){
  64. printf("Error. Exit(1)\n");
  65. exit(1);
  66. }
  67. return(0);
  68. }
При использовании обязательна ссылка на http://DMTSoft.ru
up