// =====================================================
// Проигрывание музыки с помощью таймера
//
// (C) Фролов А.В, 1997
//
// E-mail: frolov@glas.apc.org
// WWW:    http://www.glasnet.ru/~frolov
//            или
//         http://www.dials.ccas.ru/frolov
// =====================================================
#include <stdio.h>
#include <conio.h>
#include <dos.h>

void sound(int, int);
void tm_sound(int freq, int time);
void tm_delay(int ticks);

// Массив частот для мелодии
int mary[] = 
{
  330, 294, 262, 294, 330, 330, 330,
  294, 294, 294, 330, 392, 392,
  330, 294, 262, 294, 330, 330, 330, 330,
  294, 294, 330, 294, 262, 0
};

// Массив длительностей
int del[] = 
{
  5, 5, 5,  5, 5, 5,  10,
  5, 5, 10, 5, 5, 10,
  5, 5, 5,  5, 5, 5,  5, 5,
  5, 5, 5,  5, 20
};

int main(void) 
{
  int i;

  for(i=0 ;mary[i] != 0 ;i++)
    tm_sound(mary[i], del[i]);
  
  return 0;
}

/**
*.Name         tm_sound
*.Title        Формирование тона заданной длительности
*
*.Descr        Эта функция предназначена для генерации
*              на громкоговорителе тона заданной
*              длительности и частоты
*
*.Proto        void tm_sound(int freq, int time);
*
*.Params       int freq - частота в герцах;
*              int time - длительность в периодах работы
*               таймера
**/
void tm_sound(int freq, int time) 
{
  int cnt;

  // Задаем режим канала 2 таймера
  outp(0x43, 0xb6);

  // Вычисляем задержку для загрузки в
  // регистр счетчика таймера
  cnt = (int)(1193180L / freq);

  // Загружаем регистр счетчика таймера - сначала
  // младший, затем старший байты
  outp(0x42, cnt & 0x00ff);
  outp(0x42, (cnt &0xff00) >> 8);

  // Включаем громкоговоритель. Сигнал от
  // канала 2 таймера теперь будет проходить
  // на вход громкоговорителя
  outp(0x61, inp(0x61) | 3);

  // Выполняем задержку.
  tm_delay(time);

  // Выключаем громкоговоритель.
  outp(0x61, inp(0x61) & 0xfc);
}

/**
*.Name         tm_delay
*.Title        Формирование задержки по таймеру
*
*.Descr        Эта функция формирует задержку, используя
*              системный таймер
*
*.Proto        void tm_delay(int ticks)
*
*.Params       int ticks - величина задержки в периодах работы таймера
**/

void tm_delay(int ticks) 
{
  _asm 
  {
    push si

    mov  si, ticks
    mov  ah, 0
    int  1ah

    mov  bx, dx
    add  bx, si

delay_loop:

    int  1ah
    cmp  dx, bx
    jne  delay_loop

    pop  si
  }
}
