Skip to content
This repository
Browse code

QBASIC PLAY statement support for iPod

  • Loading branch information...
commit af18808bba6524a31c61e0076f0b00ae00b58a96 1 parent 3846d87
planetbeing authored May 16, 2010
15  openiboot/commands.c
@@ -1084,6 +1084,20 @@ void cmd_piezo_buzz(int argc, char** argv) {
1084 1084
 	bufferPrintf("%d hz for %u microseconds: done.\r\n", frequency, duration);
1085 1085
 }
1086 1086
 
  1087
+void cmd_piezo_play(int argc, char** argv) {
  1088
+	if(argc < 2) {
  1089
+		bufferPrintf("Usage: %s <frequency in hertz> [duration in milliseconds]\r\n", argv[0]);
  1090
+		return;
  1091
+	}
  1092
+
  1093
+	bufferPrintf("playing string \"%s\"\r\n", argv[1]);
  1094
+
  1095
+	piezo_play(argv[1]);
  1096
+
  1097
+	bufferPrintf("done\r\n");
  1098
+
  1099
+}
  1100
+
1087 1101
 #endif
1088 1102
 
1089 1103
 void cmd_help(int argc, char** argv) {
@@ -1190,6 +1204,7 @@ OPIBCommand CommandList[] =
1190 1204
 		{"audiohw_resume", "resume playback", cmd_audiohw_resume},
1191 1205
 #ifdef CONFIG_IPOD
1192 1206
 		{"buzz", "use the piezo buzzer", cmd_piezo_buzz},
  1207
+		{"play", "play notes using piezo bytes", cmd_piezo_play},
1193 1208
 #endif
1194 1209
 		{"multitouch_setup", "setup the multitouch chip", cmd_multitouch_setup},
1195 1210
 		{"help", "list the available commands", cmd_help},
2  openiboot/includes/hardware/timer.h
@@ -24,7 +24,7 @@
24 24
 #define TIMER_STATE 0x4
25 25
 #define TIMER_COUNT_BUFFER 0x8
26 26
 #define TIMER_COUNT_BUFFER2 0xC
27  
-#define TIMER_UNKNOWN2 0x10
  27
+#define TIMER_PRESCALER 0x10
28 28
 #define TIMER_UNKNOWN3 0x14
29 29
 #define TIMER_TICKSHIGH 0x80
30 30
 #define TIMER_TICKSLOW 0x84
1  openiboot/includes/piezo.h
@@ -2,5 +2,6 @@
2 2
 #define PIEZO_H
3 3
 
4 4
 void piezo_buzz(int hertz, unsigned int microseconds);
  5
+void piezo_play(const char* command);
5 6
 
6 7
 #endif
4  openiboot/includes/timer.h
@@ -10,7 +10,7 @@ typedef struct TimerRegisters {
10 10
 	uint32_t	state;
11 11
 	uint32_t	count_buffer;
12 12
 	uint32_t	count_buffer2;
13  
-	uint32_t	unknown2;
  13
+	uint32_t	prescaler;
14 14
 	uint32_t	cur_count;
15 15
 } TimerRegisters;
16 16
 
@@ -30,7 +30,7 @@ int timer_setup();
30 30
 int timer_stop_all();
31 31
 int timer_on_off(int timer_id, OnOff on_off);
32 32
 int timer_setup_clk(int timer_id, int type, int divider, uint32_t unknown1);
33  
-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);
  33
+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);
34 34
 
35 35
 uint64_t timer_get_system_microtime();
36 36
 void timer_get_rtc_ticks(uint64_t* ticks, uint64_t* sec_divisor);
285  openiboot/piezo.c
@@ -2,13 +2,292 @@
2 2
 #include "piezo.h"
3 3
 #include "timer.h"
4 4
 #include "clock.h"
  5
+#include "util.h"
5 6
 #include "hardware/timer.h"
6 7
 
  8
+static const int notes[] = {2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951};
  9
+
7 10
 void piezo_buzz(int hertz, unsigned int microseconds)
8 11
 {
9 12
 	// The second option represents the duty cycle of the PWM that drives the buzzer. In this case it is always 50%.
10  
-	timer_init(PiezoTimer, TicksPerSec / hertz / 2, TicksPerSec / hertz, 0, 0, FALSE, FALSE, FALSE, FALSE);
11  
-	timer_on_off(PiezoTimer, ON);
  13
+	if(hertz > 0)
  14
+	{
  15
+		int prescaler = 1;
  16
+		uint32_t count = TicksPerSec / hertz;
  17
+
  18
+		while(count > 0xFFFF)
  19
+		{
  20
+			count >>= 1;
  21
+			prescaler <<= 1;
  22
+		}
  23
+
  24
+		timer_init(PiezoTimer, count >> 1, count, prescaler - 1, 0, FALSE, FALSE, FALSE, FALSE);
  25
+		timer_on_off(PiezoTimer, ON);
  26
+	}
  27
+
12 28
 	udelay(microseconds);
13  
-	timer_on_off(PiezoTimer, OFF);
  29
+
  30
+	if(hertz > 0)
  31
+		timer_on_off(PiezoTimer, OFF);
  32
+}
  33
+
  34
+static inline int note_frequency(char note, int octave, int is_flat, int is_sharp)
  35
+{
  36
+	int idx;
  37
+
  38
+	if(is_flat && is_sharp)
  39
+		return -1;
  40
+
  41
+	if(octave < 0 || octave > 6)
  42
+		return -1;
  43
+
  44
+	if(note == 'C')
  45
+		idx = 0;
  46
+	else if(note == 'D')
  47
+		idx = 2;
  48
+	else if(note == 'E')
  49
+		idx = 4;
  50
+	else if(note == 'F')
  51
+		idx = 5;
  52
+	else if(note == 'G')
  53
+		idx = 7;
  54
+	else if(note == 'A')
  55
+		idx = 9;
  56
+	else if(note == 'B')
  57
+		idx = 11;
  58
+	else
  59
+		return -1;
  60
+
  61
+	if(is_flat && note == 'C')
  62
+		return -1;
  63
+
  64
+	if(is_sharp && note == 'B')
  65
+		return -1;
  66
+
  67
+	if(is_flat)
  68
+		idx = (idx - 1) % 12;
  69
+
  70
+	if(is_sharp)
  71
+		idx = (idx + 1) % 12;
  72
+
  73
+	return notes[idx]/(1 << (6 - octave));
  74
+}
  75
+
  76
+static inline unsigned int tempo_to_duration(int tempo)
  77
+{
  78
+	return 60000000U / (unsigned int) tempo;
  79
+}
  80
+
  81
+void piezo_play(const char* command)
  82
+{
  83
+	int octave = 3;
  84
+	const char* cur = command;
  85
+	unsigned int tempo = tempo_to_duration(120);
  86
+	unsigned int duration = tempo;
  87
+	int mode = 0;
  88
+
  89
+	while(*cur != '\0')
  90
+	{
  91
+		int frequency = 0;
  92
+		int cur_duration = duration;
  93
+
  94
+		if(*cur == 'O' || *cur == 'o')
  95
+		{
  96
+			octave = *(cur + 1) - '0';
  97
+			if(octave < 0 || octave > 6)
  98
+				return;
  99
+			cur += 2;
  100
+			continue;
  101
+		} else if(*cur == '<')
  102
+		{
  103
+			--octave;
  104
+			if(octave < 0 || octave > 6)
  105
+				return;
  106
+			++cur;
  107
+			continue;
  108
+		} else if(*cur == '>')
  109
+		{
  110
+			++octave;
  111
+			if(octave < 0 || octave > 6)
  112
+				return;
  113
+			++cur;
  114
+			continue;
  115
+		} else if(*cur == 'N' || *cur == 'n')
  116
+		{
  117
+			int a, b;
  118
+
  119
+			++cur;
  120
+
  121
+			a = *cur - '0';
  122
+			if(a < 0 || a > 9)
  123
+				return;
  124
+
  125
+			++cur;
  126
+
  127
+			b = *cur - '0';
  128
+			if(b >= 0 && b <= 9)
  129
+			{
  130
+				a = a * 10 + b;
  131
+				++cur;
  132
+			}
  133
+
  134
+			if(a < 0 || a > 84)
  135
+				return;
  136
+
  137
+			if(a == 0)
  138
+				frequency = 0;
  139
+			else
  140
+			{
  141
+				int xnote, xoctave;
  142
+
  143
+				xnote = (a - 1) % 12;
  144
+				xoctave = (a - 1) / 12;
  145
+
  146
+				frequency = notes[xnote] / (1 << (6 - xoctave));
  147
+			}
  148
+		} else if(*cur == 'L' || *cur == 'l')
  149
+		{
  150
+			int a, b;
  151
+
  152
+			++cur;
  153
+
  154
+			a = *cur - '0';
  155
+			if(a < 0 || a > 9)
  156
+				return;
  157
+
  158
+			++cur;
  159
+
  160
+			b = *cur - '0';
  161
+			if(b >= 0 && b <= 9)
  162
+			{
  163
+				a = a * 10 + b;
  164
+				++cur;
  165
+			}
  166
+
  167
+			if(a < 1 || a > 64)
  168
+				return;
  169
+
  170
+			duration = (tempo * 4) / a;
  171
+			continue;
  172
+		} else if(*cur == 'P' || *cur == 'p')
  173
+		{
  174
+			int a, b;
  175
+
  176
+			++cur;
  177
+
  178
+			a = *cur - '0';
  179
+			if(a < 0 || a > 9)
  180
+				return;
  181
+
  182
+			++cur;
  183
+
  184
+			b = *cur - '0';
  185
+			if(b >= 0 && b <= 9)
  186
+			{
  187
+				a = a * 10 + b;
  188
+				++cur;
  189
+			}
  190
+
  191
+			if(a < 1 || a > 64)
  192
+				return;
  193
+
  194
+			udelay((tempo * 4) / a);
  195
+			continue;
  196
+		} else if(*cur == 'T' || *cur == 't')
  197
+		{
  198
+			int a, b;
  199
+
  200
+			++cur;
  201
+
  202
+			a = *cur - '0';
  203
+			if(a < 0 || a > 9)
  204
+				return;
  205
+
  206
+			++cur;
  207
+
  208
+			b = *cur - '0';
  209
+			if(b >= 0 && b <= 9)
  210
+			{
  211
+				a = a * 10 + b;
  212
+				++cur;
  213
+			}
  214
+
  215
+			// intentionally repeated to possibly try a third character.
  216
+			b = *cur - '0';
  217
+			if(b >= 0 && b <= 9)
  218
+			{
  219
+				a = a * 10 + b;
  220
+				++cur;
  221
+			}
  222
+
  223
+			if(a < 32 || a > 255)
  224
+				return;
  225
+
  226
+			tempo = tempo_to_duration(a);
  227
+			duration = tempo;
  228
+			continue;
  229
+		} else if((*cur >= 'A' && *cur <= 'G') || (*cur >= 'a' && *cur <= 'g'))
  230
+		{
  231
+			int is_flat = 0, is_sharp = 0;
  232
+			char note = *cur;
  233
+
  234
+			++cur;
  235
+
  236
+			if(*cur == '#' || *cur == '+')
  237
+			{
  238
+				is_sharp = 1;
  239
+				++cur;
  240
+			} else if(*cur == '-')
  241
+			{
  242
+				is_flat = 1;
  243
+				++cur;
  244
+			}
  245
+
  246
+			if(note >= 'a' && note <= 'g')
  247
+				frequency = note_frequency(note - 'a' + 'A', octave, is_flat, is_sharp);
  248
+			else
  249
+				frequency = note_frequency(note, octave, is_flat, is_sharp);
  250
+
  251
+			if(frequency < 0)
  252
+				return;
  253
+		} else if(*cur == 'M' || *cur =='m')
  254
+		{
  255
+			++cur;
  256
+			if(*cur == 'N' || *cur == 'n')
  257
+			{
  258
+				mode = 0;
  259
+			} else if(*cur == 'L' || *cur == 'l')
  260
+			{
  261
+				mode = 1;
  262
+			} else if(*cur == 'S' || *cur == 's')
  263
+			{
  264
+				mode = 2;
  265
+			}
  266
+			++cur;
  267
+			continue;
  268
+		} else
  269
+		{
  270
+			++cur;
  271
+			continue;
  272
+		}
  273
+
  274
+		if(*cur == '.')
  275
+		{
  276
+			cur_duration = (cur_duration * 3) / 2;
  277
+			++cur;
  278
+		}
  279
+
  280
+		if(mode == 1)
  281
+		{
  282
+			piezo_buzz(frequency, cur_duration);
  283
+		} else if(mode == 0)
  284
+		{
  285
+			piezo_buzz(frequency, (cur_duration * 7) / 8);
  286
+			udelay(cur_duration / 8);
  287
+		} else if(mode == 2)
  288
+		{
  289
+			piezo_buzz(frequency, (cur_duration * 3) / 4);
  290
+			udelay(cur_duration / 4);
  291
+		}
  292
+	}
14 293
 }
18  openiboot/timer.c
@@ -6,19 +6,19 @@
6 6
 
7 7
 const TimerRegisters HWTimers[] = {
8 8
 		{	TIMER + TIMER_0 + TIMER_CONFIG, TIMER + TIMER_0 + TIMER_STATE, TIMER + TIMER_0 + TIMER_COUNT_BUFFER, 
9  
-			TIMER + TIMER_0 + TIMER_COUNT_BUFFER2, TIMER + TIMER_0 + TIMER_UNKNOWN2, TIMER + TIMER_0 + TIMER_UNKNOWN3 },
  9
+			TIMER + TIMER_0 + TIMER_COUNT_BUFFER2, TIMER + TIMER_0 + TIMER_PRESCALER, TIMER + TIMER_0 + TIMER_UNKNOWN3 },
10 10
 		{	TIMER + TIMER_1 + TIMER_CONFIG, TIMER + TIMER_1 + TIMER_STATE, TIMER + TIMER_1 + TIMER_COUNT_BUFFER,
11  
-			TIMER + TIMER_1 + TIMER_COUNT_BUFFER2, TIMER + TIMER_1 + TIMER_UNKNOWN2, TIMER + TIMER_1 + TIMER_UNKNOWN3 },
  11
+			TIMER + TIMER_1 + TIMER_COUNT_BUFFER2, TIMER + TIMER_1 + TIMER_PRESCALER, TIMER + TIMER_1 + TIMER_UNKNOWN3 },
12 12
 		{	TIMER + TIMER_2 + TIMER_CONFIG, TIMER + TIMER_2 + TIMER_STATE, TIMER + TIMER_2 + TIMER_COUNT_BUFFER,
13  
-			TIMER + TIMER_2 + TIMER_COUNT_BUFFER2, TIMER + TIMER_2 + TIMER_UNKNOWN2, TIMER + TIMER_2 + TIMER_UNKNOWN3 },
  13
+			TIMER + TIMER_2 + TIMER_COUNT_BUFFER2, TIMER + TIMER_2 + TIMER_PRESCALER, TIMER + TIMER_2 + TIMER_UNKNOWN3 },
14 14
 		{	TIMER + TIMER_3 + TIMER_CONFIG, TIMER + TIMER_3 + TIMER_STATE, TIMER + TIMER_3 + TIMER_COUNT_BUFFER,
15  
-			TIMER + TIMER_3 + TIMER_COUNT_BUFFER2, TIMER + TIMER_3 + TIMER_UNKNOWN2, TIMER + TIMER_3 + TIMER_UNKNOWN3 },
  15
+			TIMER + TIMER_3 + TIMER_COUNT_BUFFER2, TIMER + TIMER_3 + TIMER_PRESCALER, TIMER + TIMER_3 + TIMER_UNKNOWN3 },
16 16
 		{	TIMER + TIMER_4 + TIMER_CONFIG, TIMER + TIMER_4 + TIMER_STATE, TIMER + TIMER_4 + TIMER_COUNT_BUFFER,
17  
-			TIMER + TIMER_4 + TIMER_COUNT_BUFFER2, TIMER + TIMER_4 + TIMER_UNKNOWN2, TIMER + TIMER_4 + TIMER_UNKNOWN3 },
  17
+			TIMER + TIMER_4 + TIMER_COUNT_BUFFER2, TIMER + TIMER_4 + TIMER_PRESCALER, TIMER + TIMER_4 + TIMER_UNKNOWN3 },
18 18
 		{	TIMER + TIMER_5 + TIMER_CONFIG, TIMER + TIMER_5 + TIMER_STATE, TIMER + TIMER_5 + TIMER_COUNT_BUFFER,
19  
-			TIMER + TIMER_5 + TIMER_COUNT_BUFFER2, TIMER + TIMER_5 + TIMER_UNKNOWN2, TIMER + TIMER_5 + TIMER_UNKNOWN3 },
  19
+			TIMER + TIMER_5 + TIMER_COUNT_BUFFER2, TIMER + TIMER_5 + TIMER_PRESCALER, TIMER + TIMER_5 + TIMER_UNKNOWN3 },
20 20
 		{	TIMER + TIMER_6 + TIMER_CONFIG, TIMER + TIMER_6 + TIMER_STATE, TIMER + TIMER_6 + TIMER_COUNT_BUFFER,
21  
-			TIMER + TIMER_6 + TIMER_COUNT_BUFFER2, TIMER + TIMER_6 + TIMER_UNKNOWN2, TIMER + TIMER_6 + TIMER_UNKNOWN3 }
  21
+			TIMER + TIMER_6 + TIMER_COUNT_BUFFER2, TIMER + TIMER_6 + TIMER_PRESCALER, TIMER + TIMER_6 + TIMER_UNKNOWN3 }
22 22
 	};
23 23
 
24 24
 TimerInfo Timers[7];
@@ -63,7 +63,7 @@ int timer_setup() {
63 63
 	return 0;
64 64
 }
65 65
 
66  
-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) {
  66
+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) {
67 67
 	if(timer_id >= NUM_TIMERS || timer_id < 0) {
68 68
 		return -1;
69 69
 	}
@@ -92,7 +92,7 @@ int timer_init(int timer_id, uint32_t interval, uint32_t interval2, uint32_t unk
92 92
 	SET_REG(HWTimers[timer_id].config, config);
93 93
 	SET_REG(HWTimers[timer_id].count_buffer, interval);
94 94
 	SET_REG(HWTimers[timer_id].count_buffer2, interval2);
95  
-	SET_REG(HWTimers[timer_id].unknown2, unknown2);
  95
+	SET_REG(HWTimers[timer_id].prescaler, prescaler);
96 96
 
97 97
 	// apply the settings
98 98
 	SET_REG(HWTimers[timer_id].state, TIMER_STATE_MANUALUPDATE);

0 notes on commit af18808

Please sign in to comment.
Something went wrong with that request. Please try again.