Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

QBASIC PLAY statement support for iPod

  • Loading branch information...
commit af18808bba6524a31c61e0076f0b00ae00b58a96 1 parent 3846d87
@planetbeing authored
View
15 openiboot/commands.c
@@ -1084,6 +1084,20 @@ void cmd_piezo_buzz(int argc, char** argv) {
bufferPrintf("%d hz for %u microseconds: done.\r\n", frequency, duration);
}
+void cmd_piezo_play(int argc, char** argv) {
+ if(argc < 2) {
+ bufferPrintf("Usage: %s <frequency in hertz> [duration in milliseconds]\r\n", argv[0]);
+ return;
+ }
+
+ bufferPrintf("playing string \"%s\"\r\n", argv[1]);
+
+ piezo_play(argv[1]);
+
+ bufferPrintf("done\r\n");
+
+}
+
#endif
void cmd_help(int argc, char** argv) {
@@ -1190,6 +1204,7 @@ OPIBCommand CommandList[] =
{"audiohw_resume", "resume playback", cmd_audiohw_resume},
#ifdef CONFIG_IPOD
{"buzz", "use the piezo buzzer", cmd_piezo_buzz},
+ {"play", "play notes using piezo bytes", cmd_piezo_play},
#endif
{"multitouch_setup", "setup the multitouch chip", cmd_multitouch_setup},
{"help", "list the available commands", cmd_help},
View
2  openiboot/includes/hardware/timer.h
@@ -24,7 +24,7 @@
#define TIMER_STATE 0x4
#define TIMER_COUNT_BUFFER 0x8
#define TIMER_COUNT_BUFFER2 0xC
-#define TIMER_UNKNOWN2 0x10
+#define TIMER_PRESCALER 0x10
#define TIMER_UNKNOWN3 0x14
#define TIMER_TICKSHIGH 0x80
#define TIMER_TICKSLOW 0x84
View
1  openiboot/includes/piezo.h
@@ -2,5 +2,6 @@
#define PIEZO_H
void piezo_buzz(int hertz, unsigned int microseconds);
+void piezo_play(const char* command);
#endif
View
4 openiboot/includes/timer.h
@@ -10,7 +10,7 @@ typedef struct TimerRegisters {
uint32_t state;
uint32_t count_buffer;
uint32_t count_buffer2;
- uint32_t unknown2;
+ uint32_t prescaler;
uint32_t cur_count;
} TimerRegisters;
@@ -30,7 +30,7 @@ int timer_setup();
int timer_stop_all();
int timer_on_off(int timer_id, OnOff on_off);
int timer_setup_clk(int timer_id, int type, int divider, uint32_t unknown1);
-int timer_init(int timer_id, uint32_t interval, uint32_t interval2, uint32_t unknown2, uint32_t z, Boolean option24, Boolean option28, Boolean option11, Boolean interrupts);
+int timer_init(int timer_id, uint32_t interval, uint32_t interval2, uint32_t prescaler, uint32_t z, Boolean option24, Boolean option28, Boolean option11, Boolean interrupts);
uint64_t timer_get_system_microtime();
void timer_get_rtc_ticks(uint64_t* ticks, uint64_t* sec_divisor);
View
285 openiboot/piezo.c
@@ -2,13 +2,292 @@
#include "piezo.h"
#include "timer.h"
#include "clock.h"
+#include "util.h"
#include "hardware/timer.h"
+static const int notes[] = {2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951};
+
void piezo_buzz(int hertz, unsigned int microseconds)
{
// The second option represents the duty cycle of the PWM that drives the buzzer. In this case it is always 50%.
- timer_init(PiezoTimer, TicksPerSec / hertz / 2, TicksPerSec / hertz, 0, 0, FALSE, FALSE, FALSE, FALSE);
- timer_on_off(PiezoTimer, ON);
+ if(hertz > 0)
+ {
+ int prescaler = 1;
+ uint32_t count = TicksPerSec / hertz;
+
+ while(count > 0xFFFF)
+ {
+ count >>= 1;
+ prescaler <<= 1;
+ }
+
+ timer_init(PiezoTimer, count >> 1, count, prescaler - 1, 0, FALSE, FALSE, FALSE, FALSE);
+ timer_on_off(PiezoTimer, ON);
+ }
+
udelay(microseconds);
- timer_on_off(PiezoTimer, OFF);
+
+ if(hertz > 0)
+ timer_on_off(PiezoTimer, OFF);
+}
+
+static inline int note_frequency(char note, int octave, int is_flat, int is_sharp)
+{
+ int idx;
+
+ if(is_flat && is_sharp)
+ return -1;
+
+ if(octave < 0 || octave > 6)
+ return -1;
+
+ if(note == 'C')
+ idx = 0;
+ else if(note == 'D')
+ idx = 2;
+ else if(note == 'E')
+ idx = 4;
+ else if(note == 'F')
+ idx = 5;
+ else if(note == 'G')
+ idx = 7;
+ else if(note == 'A')
+ idx = 9;
+ else if(note == 'B')
+ idx = 11;
+ else
+ return -1;
+
+ if(is_flat && note == 'C')
+ return -1;
+
+ if(is_sharp && note == 'B')
+ return -1;
+
+ if(is_flat)
+ idx = (idx - 1) % 12;
+
+ if(is_sharp)
+ idx = (idx + 1) % 12;
+
+ return notes[idx]/(1 << (6 - octave));
+}
+
+static inline unsigned int tempo_to_duration(int tempo)
+{
+ return 60000000U / (unsigned int) tempo;
+}
+
+void piezo_play(const char* command)
+{
+ int octave = 3;
+ const char* cur = command;
+ unsigned int tempo = tempo_to_duration(120);
+ unsigned int duration = tempo;
+ int mode = 0;
+
+ while(*cur != '\0')
+ {
+ int frequency = 0;
+ int cur_duration = duration;
+
+ if(*cur == 'O' || *cur == 'o')
+ {
+ octave = *(cur + 1) - '0';
+ if(octave < 0 || octave > 6)
+ return;
+ cur += 2;
+ continue;
+ } else if(*cur == '<')
+ {
+ --octave;
+ if(octave < 0 || octave > 6)
+ return;
+ ++cur;
+ continue;
+ } else if(*cur == '>')
+ {
+ ++octave;
+ if(octave < 0 || octave > 6)
+ return;
+ ++cur;
+ continue;
+ } else if(*cur == 'N' || *cur == 'n')
+ {
+ int a, b;
+
+ ++cur;
+
+ a = *cur - '0';
+ if(a < 0 || a > 9)
+ return;
+
+ ++cur;
+
+ b = *cur - '0';
+ if(b >= 0 && b <= 9)
+ {
+ a = a * 10 + b;
+ ++cur;
+ }
+
+ if(a < 0 || a > 84)
+ return;
+
+ if(a == 0)
+ frequency = 0;
+ else
+ {
+ int xnote, xoctave;
+
+ xnote = (a - 1) % 12;
+ xoctave = (a - 1) / 12;
+
+ frequency = notes[xnote] / (1 << (6 - xoctave));
+ }
+ } else if(*cur == 'L' || *cur == 'l')
+ {
+ int a, b;
+
+ ++cur;
+
+ a = *cur - '0';
+ if(a < 0 || a > 9)
+ return;
+
+ ++cur;
+
+ b = *cur - '0';
+ if(b >= 0 && b <= 9)
+ {
+ a = a * 10 + b;
+ ++cur;
+ }
+
+ if(a < 1 || a > 64)
+ return;
+
+ duration = (tempo * 4) / a;
+ continue;
+ } else if(*cur == 'P' || *cur == 'p')
+ {
+ int a, b;
+
+ ++cur;
+
+ a = *cur - '0';
+ if(a < 0 || a > 9)
+ return;
+
+ ++cur;
+
+ b = *cur - '0';
+ if(b >= 0 && b <= 9)
+ {
+ a = a * 10 + b;
+ ++cur;
+ }
+
+ if(a < 1 || a > 64)
+ return;
+
+ udelay((tempo * 4) / a);
+ continue;
+ } else if(*cur == 'T' || *cur == 't')
+ {
+ int a, b;
+
+ ++cur;
+
+ a = *cur - '0';
+ if(a < 0 || a > 9)
+ return;
+
+ ++cur;
+
+ b = *cur - '0';
+ if(b >= 0 && b <= 9)
+ {
+ a = a * 10 + b;
+ ++cur;
+ }
+
+ // intentionally repeated to possibly try a third character.
+ b = *cur - '0';
+ if(b >= 0 && b <= 9)
+ {
+ a = a * 10 + b;
+ ++cur;
+ }
+
+ if(a < 32 || a > 255)
+ return;
+
+ tempo = tempo_to_duration(a);
+ duration = tempo;
+ continue;
+ } else if((*cur >= 'A' && *cur <= 'G') || (*cur >= 'a' && *cur <= 'g'))
+ {
+ int is_flat = 0, is_sharp = 0;
+ char note = *cur;
+
+ ++cur;
+
+ if(*cur == '#' || *cur == '+')
+ {
+ is_sharp = 1;
+ ++cur;
+ } else if(*cur == '-')
+ {
+ is_flat = 1;
+ ++cur;
+ }
+
+ if(note >= 'a' && note <= 'g')
+ frequency = note_frequency(note - 'a' + 'A', octave, is_flat, is_sharp);
+ else
+ frequency = note_frequency(note, octave, is_flat, is_sharp);
+
+ if(frequency < 0)
+ return;
+ } else if(*cur == 'M' || *cur =='m')
+ {
+ ++cur;
+ if(*cur == 'N' || *cur == 'n')
+ {
+ mode = 0;
+ } else if(*cur == 'L' || *cur == 'l')
+ {
+ mode = 1;
+ } else if(*cur == 'S' || *cur == 's')
+ {
+ mode = 2;
+ }
+ ++cur;
+ continue;
+ } else
+ {
+ ++cur;
+ continue;
+ }
+
+ if(*cur == '.')
+ {
+ cur_duration = (cur_duration * 3) / 2;
+ ++cur;
+ }
+
+ if(mode == 1)
+ {
+ piezo_buzz(frequency, cur_duration);
+ } else if(mode == 0)
+ {
+ piezo_buzz(frequency, (cur_duration * 7) / 8);
+ udelay(cur_duration / 8);
+ } else if(mode == 2)
+ {
+ piezo_buzz(frequency, (cur_duration * 3) / 4);
+ udelay(cur_duration / 4);
+ }
+ }
}
View
18 openiboot/timer.c
@@ -6,19 +6,19 @@
const TimerRegisters HWTimers[] = {
{ TIMER + TIMER_0 + TIMER_CONFIG, TIMER + TIMER_0 + TIMER_STATE, TIMER + TIMER_0 + TIMER_COUNT_BUFFER,
- TIMER + TIMER_0 + TIMER_COUNT_BUFFER2, TIMER + TIMER_0 + TIMER_UNKNOWN2, TIMER + TIMER_0 + TIMER_UNKNOWN3 },
+ TIMER + TIMER_0 + TIMER_COUNT_BUFFER2, TIMER + TIMER_0 + TIMER_PRESCALER, TIMER + TIMER_0 + TIMER_UNKNOWN3 },
{ TIMER + TIMER_1 + TIMER_CONFIG, TIMER + TIMER_1 + TIMER_STATE, TIMER + TIMER_1 + TIMER_COUNT_BUFFER,
- TIMER + TIMER_1 + TIMER_COUNT_BUFFER2, TIMER + TIMER_1 + TIMER_UNKNOWN2, TIMER + TIMER_1 + TIMER_UNKNOWN3 },
+ TIMER + TIMER_1 + TIMER_COUNT_BUFFER2, TIMER + TIMER_1 + TIMER_PRESCALER, TIMER + TIMER_1 + TIMER_UNKNOWN3 },
{ TIMER + TIMER_2 + TIMER_CONFIG, TIMER + TIMER_2 + TIMER_STATE, TIMER + TIMER_2 + TIMER_COUNT_BUFFER,
- TIMER + TIMER_2 + TIMER_COUNT_BUFFER2, TIMER + TIMER_2 + TIMER_UNKNOWN2, TIMER + TIMER_2 + TIMER_UNKNOWN3 },
+ TIMER + TIMER_2 + TIMER_COUNT_BUFFER2, TIMER + TIMER_2 + TIMER_PRESCALER, TIMER + TIMER_2 + TIMER_UNKNOWN3 },
{ TIMER + TIMER_3 + TIMER_CONFIG, TIMER + TIMER_3 + TIMER_STATE, TIMER + TIMER_3 + TIMER_COUNT_BUFFER,
- TIMER + TIMER_3 + TIMER_COUNT_BUFFER2, TIMER + TIMER_3 + TIMER_UNKNOWN2, TIMER + TIMER_3 + TIMER_UNKNOWN3 },
+ TIMER + TIMER_3 + TIMER_COUNT_BUFFER2, TIMER + TIMER_3 + TIMER_PRESCALER, TIMER + TIMER_3 + TIMER_UNKNOWN3 },
{ TIMER + TIMER_4 + TIMER_CONFIG, TIMER + TIMER_4 + TIMER_STATE, TIMER + TIMER_4 + TIMER_COUNT_BUFFER,
- TIMER + TIMER_4 + TIMER_COUNT_BUFFER2, TIMER + TIMER_4 + TIMER_UNKNOWN2, TIMER + TIMER_4 + TIMER_UNKNOWN3 },
+ TIMER + TIMER_4 + TIMER_COUNT_BUFFER2, TIMER + TIMER_4 + TIMER_PRESCALER, TIMER + TIMER_4 + TIMER_UNKNOWN3 },
{ TIMER + TIMER_5 + TIMER_CONFIG, TIMER + TIMER_5 + TIMER_STATE, TIMER + TIMER_5 + TIMER_COUNT_BUFFER,
- TIMER + TIMER_5 + TIMER_COUNT_BUFFER2, TIMER + TIMER_5 + TIMER_UNKNOWN2, TIMER + TIMER_5 + TIMER_UNKNOWN3 },
+ TIMER + TIMER_5 + TIMER_COUNT_BUFFER2, TIMER + TIMER_5 + TIMER_PRESCALER, TIMER + TIMER_5 + TIMER_UNKNOWN3 },
{ TIMER + TIMER_6 + TIMER_CONFIG, TIMER + TIMER_6 + TIMER_STATE, TIMER + TIMER_6 + TIMER_COUNT_BUFFER,
- TIMER + TIMER_6 + TIMER_COUNT_BUFFER2, TIMER + TIMER_6 + TIMER_UNKNOWN2, TIMER + TIMER_6 + TIMER_UNKNOWN3 }
+ TIMER + TIMER_6 + TIMER_COUNT_BUFFER2, TIMER + TIMER_6 + TIMER_PRESCALER, TIMER + TIMER_6 + TIMER_UNKNOWN3 }
};
TimerInfo Timers[7];
@@ -63,7 +63,7 @@ int timer_setup() {
return 0;
}
-int timer_init(int timer_id, uint32_t interval, uint32_t interval2, uint32_t unknown2, uint32_t z, Boolean option24, Boolean option28, Boolean option11, Boolean interrupts) {
+int timer_init(int timer_id, uint32_t interval, uint32_t interval2, uint32_t prescaler, uint32_t z, Boolean option24, Boolean option28, Boolean option11, Boolean interrupts) {
if(timer_id >= NUM_TIMERS || timer_id < 0) {
return -1;
}
@@ -92,7 +92,7 @@ int timer_init(int timer_id, uint32_t interval, uint32_t interval2, uint32_t unk
SET_REG(HWTimers[timer_id].config, config);
SET_REG(HWTimers[timer_id].count_buffer, interval);
SET_REG(HWTimers[timer_id].count_buffer2, interval2);
- SET_REG(HWTimers[timer_id].unknown2, unknown2);
+ SET_REG(HWTimers[timer_id].prescaler, prescaler);
// apply the settings
SET_REG(HWTimers[timer_id].state, TIMER_STATE_MANUALUPDATE);
Please sign in to comment.
Something went wrong with that request. Please try again.