Projekte
BirgerT
nibo2_MyWorx
nibo2_audio.c
Projekte
Forum
Doku
Öffentliche Projekte
Startseite
Beispielprogramme
Projekte von anderen
Welcome
Username
Passwort
Eingeloggt bleiben
Zugangsdaten vergessen?
Registrieren
Projektverwaltung
⇨ Please choose! ⇦
——————————————————
✎ Create new project...
★ Browse existing projects...
——————————————————
⚬ MotorTest#1
⚬ C Tutorial 8#1
⚬ NIBO2 C Project#1
⚙ C Tutorial 15#1
⚬ 2010_11_18_el_test001#1
nibo2_MyWorx
liesmich.txt
main.c
nibo2_akku.c
nibo2_akku.h
nibo2_audio.c
nibo2_audio.h
nibo2_audio_titels.c
nibo2_globaldef.h
nibo2_parameter.c
nibo2_parameter.h
nibo2_sensors.c
nibo2_sensors.h
nibo2_timer2.c
nibo2_timer2.h
nibo2_tour.c
nibo2_tour.h
nibo2_xbmgfx.c
nibo2_xbmgfx.h
Studio6_m...x_hex.txt
Project details
Compiler settings
Nachrichten
Sie sind nicht eingeloggt.
Neuigkeiten
★
NiboRoboLib 3.6
2017-01-17: Neue Version 3.6
★
NiboRoboLib 3.4.1
2016-04-16: Neue Version 3.4.1
★
Coding Tutorial
2015-11-22: Jetzt auch für den NIBO burger!
Site-Statistic
7427 private projects
385 public projects
16181052 lines compiled
58220 builds
NIBO
@
nibo2_MyWorx/nibo2_audio.c [read only]
/****************************************************************** Nibo2 Audio Bibliothek - BirgerT 11.07.2012 BSD License see "liesmich.txt" pitch_table und play_tone auf Basis nibo2 sounddemo von workwind play_song inspiriert durch avrbuch von Roman Mitteregger RTTTL - songs aus "nokring_tones.zip" ******************************************************************/ #include "nibo2_globaldef.h" #include "nibo2_audio.h" // Für die oekologische Notenhaltung im Flash #include <avr/pgmspace.h> /****************************************************************** Weitere RTTTL Noten/Titel sind in der Datei "nibo2_audio_titels.c" enthalten. Über TITELS 0..x können andere Titelbanken mit jeweils 16 Liedern eingebunden werden. *******************************************************************/ // #define TITELS 0 // siehe nibo2_audio_h const char PROGMEM song0[] = \ "Mosaic:d=8,o=6,b=400:c,e,g,e,c,g,e,g,c,g,c,e,c,g,e,g,e,c,p,c5,e5,g5,e5,c5,g5,e5,g5,c5,g5,c5,e5,c5,g5,e5,g5,e5,c5"; // C0, C0_, D0, D0_, E0, F0, F0_, G0, G0_, A0, A0_, H0, //"Tonleiter:d=4,o=5,b=400:b,c,c#,d.d#,e,f,f#,g,g#,a,a#,b"; #if (TITELS == 0) const char PROGMEM song1[] = \ "GetReady:d=4,o=5,b=125:8g.,8g.,8g,8c,8c,8d,8d,8g.,8g.,8g,8a#,8a#,8c6,8c6,8g.,8g.,8g,8c,8c,8d,8d,8g.,8g.,8g,8a#,8a#,8c6,8d6"; const char PROGMEM song2[] = \ //"Addams Family:d=4,o=5,b=160:8c,f,8a,f,8c,b4,2g,8f,e,8g,e,8e4,a4,2f,8c,f,8a,f,8c,b4,2g,8f,e,8c,d,8e,1f,8c,8d,8e,8f,1p,8d,8e,8f#,8g,1p,8d,8e,8f#,8g,p,8d,8e,8f#,8g,p,8c,8d,8e,8f"; "LaCucu:d=4,o=5,b=180:8c,8c,8c,f,8p,a,8p,8c,8c,8c,f,8p,a,8p,8f,8f,8e,8e,8d,8d,c,p,8c,8c,8c,e,8p,g,8p,8c,8c,8c,e,8p,g,8p,8c6,8b,8c6,8a#,8a,8g,f"; const char PROGMEM song3[] = \ "Axel F:d=4,o=5,b=125:g,8a#.,16g,16p,16g,8c6,8g,8f,g,8d.6,16g,16p,16g,8d#6,8d6,8a#,8g,8d6,8g6,16g,16f,16p,16f,8d,8a#,2g,p,16f6,8d6,8c6,8a#,g,8a#.,16g,16p,16g,8c6,8g,8f,g,8d.6,16g,16p,16g,8d#6,8d6,8a#,8g,8d6,8g6,16g,16f,16p,16f,8d,8a#,2g"; const char PROGMEM song4[] = \ "Entertainer:d=4,o=5,b=140:8d,8d#,8e,c6,8e,c6,8e,2c.6,8c6,8d6,8d#6,8e6,8c6,8d6,e6,8b,d6,2c6,p,8d,8d#,8e,c6,8e,c6,8e,2c.6,8p,8a,8g,8f#,8a,8c6,e6,8d6,8c6,8a,2d6"; const char PROGMEM song5[] = \ "Flintstones:d=4,o=5,b=200:g#,c#,8p,c#6,8a#,g#,c#,8p,g#,8f#,8f,8f,8f#,8g#,c#,d#,2f,2p,g#,c#,8p,c#6,8a#,g#,c#,8p,g#,8f#,8f,8f,8f#,8g#,c#,d#,2c#"; const char PROGMEM song6[] = \ "Indiana Jones:d=4,o=5,b=250:e,8p,8f,8g,8p,1c6,8p.,d,8p,8e,1f,p.,g,8p,8a,8b,8p,1f6,p,a,8p,8b,2c6,2d6,2e6,e,8p,8f,8g,8p,1c6,p,d6,8p,8e6,1f.6,g,8p,8g,e.6,8p,d6,8p,8g,e.6,8p,d6,8p,8g,f.6,8p,e6,8p,8d6,2c6"; const char PROGMEM song7[] = \ "Pink Panther:d=4,o=5,b=160:8d#,8e,2p,8f#,8g,2p,8d#,8e,16p,8f#,8g,16p,8c6,8b,16p,8d#,8e,16p,8b,2a#,2p,16a,16g,16e,16d,2e"; const char PROGMEM song8[] = \ "Simpsons:d=4,o=5,b=160:c.6,e6,f#6,8a6,g.6,e6,c6,8a,8f#,8f#,8f#,2g,8p,8p,8f#,8f#,8f#,8g,a#.,8c6,8c6,8c6,c6"; const char PROGMEM song9[] = \ "Agadoo:d=4,o=5,b=125:8b,8g#,e,8e,8e,e,8e,8e,8e,8e,8d#,8e,f#,8a,8f#,d#,8d#,8d#,d#,8d#,8d#,8d#,8d#,8c#,8d#,e"; const char PROGMEM songA[] = \ "Auld L S:d=4,o=5,b=100:g,c.6,8c6,c6,e6,d.6,8c6,d6,8e6,8d6,c.6,8c6,e6,g6,2a.6,a6,g.6,8e6,e6,c6,d.6,8c6,d6,8e6,8d6,c.6,8a,a,g,2c.6"; const char PROGMEM songB[] = \ "Barbie girl:d=4,o=5,b=125:8g#,8e,8g#,8c#6,a,p,8f#,8d#,8f#,8b,g#,8f#,8e,p,8e,8c#,f#,c#,p,8f#,8e,g#,f#"; const char PROGMEM songC[] = \ "Birdy S:d=4,o=5,b=100:16g,16g,16a,16a,16e,16e,8g,16g,16g,16a,16a,16e,16e,8g,16g,16g,16a,16a,16c6,16c6,8b,8b,8a,8g,8f,16f,16f,16g,16g,16d,16d,8f,16f,16f,16g,16g,16d,16d,8f,16f,16f,16g,16g,16a,16b,8c6,8a,8g,8e,c"; const char PROGMEM songD[] = \ "Death:d=4,o=5,b=100:c.,c,8c,c.,d#,8d,d,8c,c,8c,2c."; const char PROGMEM songE[] = \ "Final Countdown:d=4,o=5,b=125:p,8p,16b,16a,b,e,p,8p,16c6,16b,8c6,8b,a,p,8p,16c6,16b,c6,e,p,8p,16a,16g,8a,8g,8f#,8a,g.,16f#,16g,a.,16g,16a,8b,8a,8g,8f#,e,c6,2b.,16b,16c6,16b,16a,1b"; const char PROGMEM songF[] = \ "Deutschlandlied:d=4,o=5,b=160:2g,8a,b,a,c6,b,8a,8f#,g,e6,d6,c6,b,a,8b,8g,2d6,2g,8a,b,a,c6,b,8a,8f#,g,e6,d6,c6,b,a,8b,8g,2d6,a,b,8a,8f#,d,c6,b,8a,8f#,d,d6,c6,2b,8b,c#6,8c#6,8d6,2d6,2g6,8f#6,8f#6,8e6,d6,2e6,8d6,8d6,8c6,b,2a,16b,16c6,8d6,8e6,8c6,8a,2g,8b,8a,2g"; // weitere RTTTL-Titel in more_titels.inc #elif (TITELS > 0) #include "nibo2_audio_titels.c" #endif /***************************************************** TITEL STARTADRESSE audio_start_titel_P() gibt 15 Zeichen Titeltext aus dem RTTTL-Song auf dem Grafikdisplay aus. -> nr = Titelindex (Titelnummer-1) in der songs[] Liste <- Startadresse des RTTTL Notenstrings im Flash Der Zeiger wird zur Titelanzeige mit show_titel() verwendet und / oder an den RTTL Parser play_song() übergeben **************************************************************************/ const char * PROGMEM const songs[] = {song0,song1,song2,song3,song4,song5,song6,\ song7,song8,song9,songA,songB,songC,songD,songE,songF}; PGM_P audio_start_titel_P(uint8_t nr){ // ACHTUNG: Index ist ein Wort, deshalb nr auf halbe Arraygröße begrenzen if (nr >= (sizeof(songs)/sizeof(songs[0]))) nr =0; return (const char*)(pgm_read_word(&(songs[nr]))); } /**************************************************** ZEICHEN RINGBUFFER Die Laenge der Ringbuffer muss einer 2er Potenz (16,32,64 oder 128) entsprechen, damit der Zeiger Rollover vom Ende an Anfang mit einer Bitmaske gemacht werden kann. Zeiger == 15 (0b00001111) Zeiger == 32 (0b00100000 Bufferende) Bitmaske == 31 (0b00011111 Bufferlen - 1) Zeiger &= Bitmaske (0b00001111 bzw. 0b00000000) ***************************************************************************/ #define NOTEN_BUF_MASK ( NOTEN_BUF_LEN - 1) #if ( NOTEN_BUF_LEN & NOTEN_BUF_MASK ) #error Noten Buffer Laenge ist keine 2er Potenz #endif static volatile uint16_t Noten_Buffer[NOTEN_BUF_LEN]; static volatile uint8_t Noten_InPtr; static volatile uint8_t Noten_OutPtr; /************************************************************ PITCH TABLE (c) Nils Springob @ nicai-systems Timer Werte für die verschiedenen Noten. Die Werte gehen über 2 Oktaven, der weitere Tonumfang wird über die Konfiguration des Timers erreicht. Die Werte werden als TOP Wert in den Timer geladen (er zählt also bis zum Erreichen des Wertes, invertiert den Port-Pin und fängt dann wieder von vorne an zu zählen. Infos: http://de.wikipedia.org/wiki/Oktave http://www.sengpielaudio.com/Rechner-notennamen.htm (MIDI Noten und die dazugehörenden Frequenzen) Die Frequenz für ein C berechnet sich aus: f = 8.176 Hz * (2^Oktave) Ein Dis berechnet sich aus: f = 9.723 * (2^Oktave) Der Timer kann von 1 bis 256 zählen. Die Timer-Werte müssen also in dem Intervall landen: 1953/8.176 = 238 (niedrigster Ton C0) 1953/(2*15.434) = 63 (höchster Ton H1) Um die nächste Oktave zu ereichen lässt man den Timer einfach doppelt so schnell laufen. Da der Timer jedoch häufig nur Vierer-Schritte anbietet, muss man zwei Oktaven überspringen und den Timer dann 4 mal so schnell laufen lassen. **************************************************************************/ const uint8_t PROGMEM pitch_table [] = { //const uint8_t pitch_table [] = { /* 1. Oktave */ 1953/8.176, 1953/8.662, 1953/9.177, 1953/9.723, 1953/10.301, 1953/10.913, 1953/11.562, 1953/12.250, 1953/12.987, 1953/13.750, 1953/14.568, 1953/15.434, /* 2. Oktave */ 1953/(2*8.176), 1953/(2*8.662), 1953/(2*9.177), 1953/(2*9.723), 1953/(2*10.301), 1953/(2*10.913), 1953/(2*11.562), 1953/(2*12.250), 1953/(2*12.987), 1953/(2*13.750), 1953/(2*14.568), 1953/(2*15.434) }; /******************************************************* NOTE IN BUFFER audio_play_tone() eine einzelne Note in den Notenbuffer legen -> pitch = Nummer der Note aus der Notentabelle duration = Tonlänge in 10 ms Schritten <- FALSE = Notenbuffer voll, Note nicht abgelegt **********************************************************************/ uint8_t audio_play_tone(uint8_t pitch, uint8_t duration) { if (duration) duration--; // Eingabe Zeiger Rollover uint8_t TempPtr = (Noten_InPtr + 1) & NOTEN_BUF_MASK; // Freien Platz prüfen !! if(TempPtr == Noten_OutPtr){ return(FALSE); } // Zeichen in Buffer schreiben Noten_Buffer[TempPtr] = MAKEWORD(pitch,duration); // Neuer Eingabe Zeiger Noten_InPtr = TempPtr; return(TRUE); } /********************************************* TIMER2 ISR: NOTE SPIELEN Timer0 Prescaler Setup (c) Nils Springob @ nicai-systems audio_ISR_T2() Funktion wird alle 10ms aus der ISR Timer 2 aufgerufen. Aus einer Note im Notenbuffer die Rresets für den SoundTimer 0 ermitteln und setzen. **********************************************************************/ void audio_ISR_T2(void){ static uint8_t status = STOP; static uint8_t dauer = 0; uint8_t pitch; // Nach jeder Note eine Pause 10 ms einlegen // Wenn Wartepause Ende dann Status gestoppt if(status == PAUSE) status = STOP; // wird Note gespielt ? if(dauer > 0) { dauer--; } else { // Am Notenende eine Pause (10ms) einfügen if(status == PLAY) status = PAUSE; // Timer 0 still TCCR0 = 0x00; } // Sound Timer bereit? if(status == STOP){ // Ist noch eine Note im Buffer zu spielen? if (Noten_InPtr != Noten_OutPtr) { // Neuen AustragsZeiger in Buffer berechnen // mit Zeiger Rollover uint8_t TempPtr = (Noten_OutPtr + 1) & NOTEN_BUF_MASK; // Notenwerte lesen.. uint16_t TempNote = Noten_Buffer[TempPtr]; // ..und zerlegen dauer = LOBYTE(TempNote); pitch = HIBYTE(TempNote); // Neuen Bufferzeiger speichern Noten_OutPtr = TempPtr; status = PLAY; // Pause ohne Ton.im Notenbuffer if (pitch==P__) { TCCR0 = 0x00; OCR0 = 0x00; } else // **************************************Timer0 Prescaler Setup { /* Prescaler für Timer 0 nach Oktave wählen (2^Oktave...) */ if (pitch>=C6) { /* Oktaven 6 und 7 */ /* Timergeschwindigkeit 1 (PS=8) */ TCCR0 = 0x1a; pitch -= 12*6; /* 6 Oktaven abziehen, dafür Timer 64 (2^6) mal so schnell */ } else if (pitch>=C5) { /* Oktave 5 */ /* Timergeschwindigkeit 1 (PS=32) */ TCCR0 = 0x1b; pitch -= 12*5; /* 5 Oktaven abziehen, dafür Timer 32 (2^5) mal so schnell */ } else if (pitch>=C4) { /* Oktave 4 */ /* Timergeschwindigkeit 1 (PS=64) */ TCCR0 = 0x1c; pitch -= 12*4; /* 4 Oktaven abziehen, dafür Timer 16 (2^4) mal so schnell */ } else if (pitch>=C3) { /* Oktave 3 */ /* Timergeschwindigkeit 1 (PS=128) */ TCCR0 = 0x1d; pitch -= 12*3; /* 3 Oktaven abziehen, dafür Timer 8 (2^3) mal so schnell */ } else if (pitch>=C2) { /* Oktave 2 */ /* Timergeschwindigkeit 1 (PS=256) */ TCCR0 = 0x1e; pitch -= 12*2; /* 2 Oktaven abziehen, dafür Timer 4 (2^2) mal so schnell */ } else { /* Oktave 0 und 1 */ /* Timergeschwindigkeit 1 (PS=1024) */ TCCR0 = 0x1f; } /* Timer Wert aus der Note berechnen */ OCR0 = pgm_read_byte(&(pitch_table[pitch])); } } else { // Song ist gespielt Audio_Status = READY; } } } /************************************************** AUDIO INIT audio_init() übergibt die Adresse der Funktion zum Abspielen einer Note an die ISR Taskliste des Timer 2. ****************************************************************/ volatile uint8_t Audio_Status = STOP; void audio_init(void){ /* AUDIO Pin auf Ausgang schalten */ activate_output_bit(IO_AUDIO); Audio_Status = STOP; /* AUDIO ISR in Timer2 ISR anmelden */ timer2_init(&audio_ISR_T2); } // Akürzungsmakro #define PRB(p) pgm_read_byte(p) /************************************************ TITEL ANZEIGEN audio_show_titel_P() gibt 15 Zeichen Titeltext aus dem RTTTL-Song auf dem Grafikdisplay aus. -> x-,y- Position für Textausgabe Adresse des Titelanfangs im Flash ****************************************************************/ // Grafikdisplay aus nibo_config.h? #ifdef NIBO_USE_GFX void audio_show_titel_P(uint8_t x, uint8_t y, PGM_P song){ gfx_draw_mode(GFX_DM_JAM2); // ueberschreiben gfx_move(x,y); /* gfx_set_proportional(1); gfx_print_text("NOW PLAYING: "); gfx_move(x,y+12); */ for(uint8_t i = 0; i < 15; i++){ char c = PRB(song); if((c >= ' ') && (c != ':')) { gfx_print_char(c); song++; } else { // Leerzeichen auffüllen gfx_print_char(' '); } } } #endif /************************************************** RTTTL PARSER audio_play_song_P() liest einen Song im RTTTL Format aus dem Flash und gliedert ihn in einzelne Noten (pitch, duration). Die Noten werden über audio_play_note() in den Ausgabebuffer für die Interupt Funktion abgelegt, bis der Buffer voll ist oder der gesamte Titel abgearbeitet wurde. Die Funktion muss zyklisch aufgerufen werden, um den Buffer weiter zu füllen. -> Adresse des Titelanfangs im Flash <- TRUE == Noten in Buffer abgelegt, FALSE == Buffer voll ***************************************************************/ PGM_P song_ptr = 0; // Zeiger auf aktuelle Note uint8_t std_notenlaenge = 4; // Standard Viertelnoten uint8_t std_oktave = 5; // Standard Oktave uint16_t bpm = 100; // Anzahl Viertelnoten / Minute uint8_t notenlaenge = 4; // RTTTL Notenlänge uint8_t oktave = 5; // RTTTL Oktave uint8_t punktiert = 0; // Merker für punktierte Note uint8_t pitch = P__; // Merker aktuelle Note // ***********************************************/ uint8_t audio_play_song_P(PGM_P song) { // Wird ein neuer Song gespielt if((song_ptr == 0) && (song != 0)){ // Skip Titel while(PRB(song) != ':'){ if(PRB(song) < ' ') return(FALSE); song++; } song++; // Skip Doppelpunkt // Song-Information Standardparameter auslesen while (PRB(song) != ':'){ uint8_t para = PRB(song++); // Parameter o, d, b merken song++; //skip '=' uint8_t wert = 0; // Paramterwert mit selbstgebasteltem atoi while((PRB(song) >= '0') && (PRB(song) <= '9')){ wert = wert * 10 + (PRB(song) - '0'); song++; } switch (para) { case 'b': bpm = wert; break; case 'd': std_notenlaenge = wert; break; case 'o': std_oktave = wert; break; } if(PRB(song) == ',') song++; // skip Komma } song++; // Skip Doppelpunkt } // Der Song wurde zuende gespielt else if ((Audio_Status == ENDE) || (Audio_Status == READY)) { return(FALSE); } // an aktueller Songposition fortsetzen else{ song = song_ptr; // an alter Position weitermachen } /******************************************* Noten parsen */ while (PRB(song) >= ' ') { /*************************************** Buffer testen */ uint8_t TempPtr = (Noten_InPtr + 1) & NOTEN_BUF_MASK; // Kein freier Platz im Buffer ? if(TempPtr == Noten_OutPtr){ song_ptr = song; // Position merken return(FALSE); // und Tschuess } /************************************* Note analysieren */ // Wurde eine Tonlänge angegeben? */ if(PRB(song) >= '0' && PRB(song) <= '9') { notenlaenge = 0; while(PRB(song) >= '0' && PRB(song) <= '9'){ notenlaenge = notenlaenge * 10 + (PRB(song) - '0'); song++; } } else { notenlaenge = std_notenlaenge; } // Noten in pitch wandeln switch (PRB(song++)) { case 'c': pitch = C0; break; case 'd': pitch = D0; break; case 'e': pitch = E0; break; case 'f': pitch = F0; break; case 'g': pitch = G0; break; case 'a': pitch = A0; break; case 'b': pitch = H0; break; case 'p': pitch = P__; break; /* pause! */ } // Halbtoene == pitch +1 if(PRB(song) == '#'){ // case 'c': pitch = C0_; break; /* c# */ // case 'd': pitch = D0_; break; /* d# */ // case 'f': pitch = F0_; break; /* f# */ // case 'g': pitch = G0_; break; /* g# */ // case 'a': pitch = A0_; break; /* a# */ pitch++; song++; } // "Dot" = Punktierte Note ... punktiert = 0; if(PRB(song) == '.'){ punktiert = 1; song++; } // Oktave ... oktave = std_oktave; if(PRB(song) >= '0' && PRB(song) <= '9') { oktave = (PRB(song) - '0'); song++; } // RTTTL Oktaven 5..8 in Nibo2 Oktaven 4..7 if(oktave > 0) oktave--; // 12 Noten / Oktave pitch += (12 * oktave); // "Dot" = Punktierte Note ... if(PRB(song) == '.'){ punktiert = 1; song++; } // wenn noch 'ne Note kommt if(PRB(song) == ',') { song++; // Skip Komma } else { // Song ist zu Ende song_ptr = 0; } /************************************* Note Spieldauer */ // BPM = Schläge pro Minute = Viertelnoten / Minute uint16_t taktlaenge = (6000 / bpm); // taktlaenge in 10ms switch (notenlaenge) { case 1: taktlaenge = taktlaenge * 4; break; case 2: taktlaenge = taktlaenge * 2; break; // case 4: taktlaenge = taktlaenge; break; // bpm = viertelnoten case 8: taktlaenge = taktlaenge / 2; break; case 16: taktlaenge = taktlaenge / 4; break; case 32: taktlaenge = taktlaenge / 8; break; } if(punktiert) taktlaenge += taktlaenge/2; /******************************************* Ton erzeugen */ if(audio_play_tone(pitch, taktlaenge) == FALSE) return(FALSE); Audio_Status = PLAY; } // while Audio_Status = ENDE; return(TRUE); } // Baustelle: Player Kommandos uint8_t audio_cmd(uint8_t cmd){ return(Audio_Status); }
Compiler results:
Werbung
Online
Bogdancmd
bradlygoi441228704773
josch
paulinegonsalves19
sashaserrano161
taracfj57630663