====== OSA usage example: QUARTET ====== ===== Project ===== Program **quartet** synthesizes melody by given notes (it plays part of J.S.Bach N1067). Unpack file {{osa:quartet4.rar|quartet4.rar}} into foulder "C:\TEST\QUARTET". This project is written for PIC16F628A. This program generates 4-channel melody, using 8-bit PWM at 78 KHz. Music is played with four samples: bass, violin and two guitars (of course, my samples are very different from reality). Each channel can be switched ON or OFF by switches. Here is ##MP3## ({{osa:quartet_mp3.rar|download}}), recorded from device's output. ===== Scheme ===== The scheme of device is below. 8-bit digital signal from PWM through RC-filter R22-C3 and volume regulator R24 goes to headphones. {{osa:ref:appendix:quartet_pwm.jpg}} Switch ##SW1## switchs bass ON/OFF.\\ Switch ##SW2## switchs voilin ON/OFF.\\ Switch ##SW3## switchs first guitar ON/OFF.\\ Switch ##SW4## switchs second guitar ON/OFF.\\ ===== Description ===== Program consists of four files: * **quartet_main.c** - main program: tasks and notes working functions. * **music.c** - contains frequencies table and notelists for each channel. * **sinus.c** - contains three arrays with sinus data for each instrument (bass, violin, guitar). * **interrupt.c** - interrupt function. It contains code of synthesizer (called every 100 us). **quartet_main.c** described below. Program consists of 5 tasks. Four of them are "musicants", and fifth is "conductor" that sinchronize first four tasks. ==== Sound control ==== To control sound type **TSound** defined in **quartet_main.c**. Variables of this type contains all sound information for "musicant": * current note; * notelist; * is "musicant" in pause; * is "musicant" repeats fragment; for "conductor": * when it must give next command to "musicant"; * did "musicant" stop playing (reach end of nitelist) for synthesiser: * current sound frequency; * time of playing current note (to form envelope for signal). ==== "Musicants" ==== There are four "musicants" in program: Task_BASS, Task_VIOLIN, Task_GUITAR1, Task_GUITAR2. All time "musicants" wait for command from "conductor" (binary semaphore). When getting command, "musicant" reads next note from his notelist, plays it (task forms data for synthesizer). Note produced in **NoteWork()** function, witch gets variable of sound control TSound in parameters. Using data of this variable function reads next note (or instruction: repeat, pause, ect.) and makes several operations to form parameters to synthesizer, in addition this function forms duration varianble. This variable decreases on every command from "conductor". When "musicant" reaches the end of notelist, he informs "conductor" about it (task clears corresponding bit in flag variable **flags_Playing**). After that "musicant" begins to wait for "conductor's" command to restart music (binary semaphore BS_START). When "musicant" gets it, he goes to begin of notelist (sound control variable re-initializates) and sends "conductor's" command to next"musicant". ==== "Conductor" ==== Taks_CONDUCTOR ("conductor") has priority lower then "musicants". "Conductor" counts ticks like metronome and looks to ensure that all "musicants" get commands at correct time. Task_CONDUCTOR gets control every 150 ms. On every execution it checks for music state. When "conductor" determines that all "musicants" stopped to play (all bits in flag variable **flag_Playing** are cleared), he sends command to "musicants" to restart musig from the begin. ==== Two words about synthesizer ==== Sinthesizer is placed into interrupt routine if file **interrupt.c**. Interrupt takes all sound control variables and forms digital signal. To make this work it has: * three tables of sound patterns for each sample: bass[], violin[], guitar[] (see sinus.c). This arrays contains one sinus period per each sample. * envelope formulas (see comments FORMING_SIGNAL_xxx): attack, release, ect. * macro for fast multiplication (char) = high( (signed char)*(unsigned char) ), to multiply sinus value by enveloping amplitude. All four current values of sound are summed up, and then result is divided by four. After that result copies into m_cDAC variable. On next start of interrupt routine this variable will be copied into PWM buffer register CCPR1L (two least significant bits are copied into bits CCP1X and CCP1Y of CCP1CON register). ==== About notelists ==== Few information about notelist will help you to create your music. File **music.c** contains definitions for notes: C0, C0_, D0, D0_, ect. There are definitons for 57 frequencies (four with half octaves). When we create note in notelist (arrays **notelist_xxx**) using macro **play()**, we can to set note only with 5 bits (32 notes). Therefore there is possibleness to set base octave (macro **setbase()**). Note duration is selected using only 2 bits, so only four durations can be set. If you need note with longest duration, you can use either macro **pause()** (pauses sound by several ticks) or macro **playmore()** (continue playing sound for several ticks). Notelist must be ended with macro **stop()** to avoid reading unitializes memory cells.