?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{FILE START}

library

?curdirlinks? - Rev 3

?prevdifflink? - Blame - ?getfile?

// Knihovna pro generovani hudebnich zvuku dane frekvence a delky nebo
// dane noty temperovaneho ladeni a delky.
//
// Pro generovani nepouziva zadnou podporu HW, vse se generuje ciste SW.
//
// (c)miho 2003
//
// Historie
// 1.00 Uvodni verze
//


// Konfiguracni parametry
//#define SOUND_HI     PIN_xx          // Pozitivni vystup
//#define SOUND_LO     PIN_xx          // Komplementarni vystup
#ifndef SOUND_REZIE
#define SOUND_REZIE  72                // Piskvorcova konstanta zahrnuje celkovou rezii ve smycce
#endif
#ifndef SOUND_CLOCK
#define SOUND_CLOCK  4000000           // Frelvence krystalu v Hz
#endif


// Definice hudebnich tonu (not) pro proceduru SoundNote()
#define SOUND_C     0
#define SOUND_Cis   1
#define SOUND_D     2
#define SOUND_Dis   3
#define SOUND_E     4
#define SOUND_F     5
#define SOUND_Fis   6
#define SOUND_G     7
#define SOUND_Gis   8
#define SOUND_A     9
#define SOUND_Ais   10
#define SOUND_H     11
#define SOUND_Space 12                 // Pomlka


// Prototypy verejnych procedur

void SoundBeep(unsigned int16 Frequency, unsigned int16 Duration);
// Predava se frekvence v Hz a doba trvani v ms (0 znamena ticho)

void SoundNote(unsigned int8 Note, Octave, unsigned int16 Duration);
// Predava se cislo noty (0 je C), posunuti v oktavach (0 nejnizsi ton,
// SOUND_Space je ticho), doba trvani v ms

// Alternativni makra pro generovani konstatnich tonu
// SoundBeepMacro(Frequency, Duration) - frekvence nesmi byt 0
// SoundNoteMacro(Note, Octave, Duration) - nepodporuje SOUND_Space
// SoundSpaceMacro(Duration) - hraje ticho

// Privatni cast


#ORG 0x100, 0x128                      // Aby skok nebyl pres hranici 0x100
void DelaySpecial(unsigned int16 Time)
// Pomocna procedura pro mereni spozdeni s granularitou 1 instrukcni takt
// Cas v instrukcnich cyklech, skutecny cas je vetsi o _konstantni_ rezii
// Maximalni cas je 65536 us
{
   unsigned int8 TimeHi;               // Pro pristup k horni casti Time

      *0x0A = LABEL_ADDRESS(Next)>>8;  // Nastav PCLATH
   #asm
      movf     Time,w                  // Zpracuj nejnizsi 3 bity
      xorlw    7                       // Pro hodnotu 0 skakej pres vsechny nopy
      andlw    7                       // Ber jen spodni 3 bity
      addwf    2,f                     // Preskoc zadny az vsech 8 nopu (2 je PCL)
   Next:
      nop                              // Spozdeni s granularitou 1 takt
      nop
      nop
      nop
      nop
      nop
      nop
      nop
   #endasm
   Time = Time >> 3;                   // Zahod spodni 3 bity
   TimeHi=Time>>8;                     // Oddel horni cast citace
   Time++;                             // Korekce na casovani typu dcfsz
   TimeHi++;
   #asm
   Loop:
      nop                              // Smycka musi trvat 8 taktu
      nop                              //   a ma 16 bitu dlouhy citac
      nop
      decfsz   Time
      goto     Next1
      decfsz   TimeHi
   Next1:
      goto     Loop
   #endasm

}


unsigned int32 SoundCount;             // Pocet pulperid geneovaneho signalu
unsigned int32 SoundPeriod;            // Delka pulperiody v us (zmensene o SOUND_REZIE)


void SoundLoop()
// Pomocna funkce - hlavni zvukova smycka
{
   int1 Data;
   unsigned int16 i;

   for(i=SoundCount;i>0;i--)           // Pocet pulperiod
   {
      output_bit(SOUND_HI,Data);       // Nastav vystup
      output_bit(SOUND_LO,~Data);
      Data=~Data;                      // Otoc stav vystupu
      DelaySpecial(SoundPeriod);       // Pockej po dobu plperiody
   }
}


void SoundBeep(unsigned int16 Frequency, unsigned int16 Duration)
// Predava se frekvence v Hz a doba trvani v ms (0 znamena ticho)
// Rozumne frekvence jsou v rozsahu cca 10Hz az 5000Hz pro krystal 4MHz,
// cas do cca 5s (2*Cas/1000*Freq musi byt < nez 65536)
{
   if (Frequency==0)
   {
      for(;Duration>0;Duration--)
      {
         DelaySpecial(1000);           // Zhruba 1ms
      }
      return;
   }

   SoundPeriod=(SOUND_CLOCK/4/2)/Frequency-SOUND_REZIE;

   SoundCount=Duration;                // Vypocet poctu pulperiod signalu Duration*Frequency*2/1000
   SoundCount*=Frequency;
   SoundCount/=500;

   SoundLoop();                         // Pozor pouzivaji se globalni parametry
}

// Definice casu pulperody pro nejnizsi oktavu, v mikrosekundach
// Periody tonu v dalsich oktavach se ziskavaji rotaci vpravo
#define SOUND_Peri_C    (30578*(SOUND_CLOCK/1000)/1000/4/2)       // Perioda 30578us
#define SOUND_Peri_Cis  (28862*(SOUND_CLOCK/1000)/1000/4/2)       // Perioda 28862us
#define SOUND_Peri_D    (27242*(SOUND_CLOCK/1000)/1000/4/2)       // Perioda 27242us
#define SOUND_Peri_Dis  (25713*(SOUND_CLOCK/1000)/1000/4/2)       // Perioda 25713us
#define SOUND_Peri_E    (24270*(SOUND_CLOCK/1000)/1000/4/2)       // Perioda 24270us
#define SOUND_Peri_F    (22908*(SOUND_CLOCK/1000)/1000/4/2)       // Perioda 22908us
#define SOUND_Peri_Fis  (21622*(SOUND_CLOCK/1000)/1000/4/2)       // Perioda 21622us
#define SOUND_Peri_G    (20408*(SOUND_CLOCK/1000)/1000/4/2)       // Perioda 20408us
#define SOUND_Peri_Gis  (19263*(SOUND_CLOCK/1000)/1000/4/2)       // Perioda 19263us
#define SOUND_Peri_A    (18182*(SOUND_CLOCK/1000)/1000/4/2)       // Perioda 18182us
#define SOUND_Peri_Ais  (17161*(SOUND_CLOCK/1000)/1000/4/2)       // Perioda 17161us
#define SOUND_Peri_H    (16198*(SOUND_CLOCK/1000)/1000/4/2)       // Perioda 16198us

#if SOUND_Peri_C > 65535
#error "Sound Clock too high (Note C requires delay > 65535 cycles)"
#endif

const int16 Table[12] = SOUND_Peri_C,     SOUND_Peri_Cis,   SOUND_Peri_D,     SOUND_Peri_Dis,
                        SOUND_Peri_E,     SOUND_Peri_F,     SOUND_Peri_Fis,   SOUND_Peri_G,
                        SOUND_Peri_Gis,   SOUND_Peri_A,     SOUND_Peri_Ais,   SOUND_Peri_H;

void SoundNote(unsigned int8 Note, Octave, unsigned int16 Duration)
// Predava se cislo noty (0 je C), posunuti v oktavach (0 nejnizsi ton)
// doba trvani v ms (0 znamena ticho)
// Zahraje zadanou notu v zadane oktave dane delky
{

   if (Note==SOUND_Space)
   {
      for(;Duration>0;Duration--)
         DelaySpecial(1000);           // Zhruba 1ms
      return;
   }

   SoundPeriod=(Table[Note]>>Octave)-0;   // Zde je chyba prekladace, nula musi zusat

   SoundCount=Duration;
   SoundCount*=1000;
   SoundCount/=SoundPeriod;

   SoundPeriod=SoundPeriod-SOUND_REZIE;

   SoundLoop();                         // Pozor pouzivaji se globalni parametry
}


// Sada maker, ktera neobsahuji slozity vypocet a jsou
// tedy vhodna pro jednoduche pipnuti. Parametry jsou stejne
// jako o funkci.
#define SoundBeepMacro(F,D)                     \
   SoundPeriod=SOUND_CLOCK/4/2/F-SOUND_REZIE;   \
   SoundCount=D*F/500;                          \
   SoundLoop();

#define SoundNoteMacro(N,O,D)                   \
   SoundPeriod=(Table[N]>>O)-SOUND_REZIE;       \
   SoundCount=D*1000/(Table[N]>>O);             \
   SoundLoop();

#define SoundPauseMacro(D)                      \
   {                                            \
      #if D>255                                 \
      unsigned int16 i=D;                       \
      #else                                     \
      unsigned int8  i=D;                       \
      #endif                                    \
      for(;i>0;i--)                             \
      {                                         \
         DelaySpecial(1000);                    \
      }                                         \
   }
{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3