1 /*
2  * GQradio
3  * (C) 2005 John Ellis
4  *
5  * Author: John Ellis
6  *
7  * This software is released under the GNU General Public License (GNU GPL).
8  * Please read the included file COPYING for more information.
9  * This software comes with no warranty of any kind, use at your own risk!
10  */
11 
12 #include "gqradio.h"
13 
14 #include "display.h"
15 #include "io_radio.h"
16 #include "mixer.h"
17 #include "preset.h"
18 #include "rcfile.h"
19 #include "ui2_editor.h"
20 #include "ui2_main.h"
21 #include "ui2_util.h"
22 #include "ui_fileops.h"
23 #include "ui_tabcomp.h"
24 #include "ui_utildlg.h"
25 #include "window.h"
26 
27 
28 #define RADIO_SLOW_SEEK 4
29 #define RADIO_SLOW_THRESHHOLD 4
30 
31 static gint main_loop_id = -1;
32 
33 static gint auto_seeking = 0;
34 static gint auto_seek_signal = -1;
35 static guint32 auto_seek_freq = 0;
36 
37 static gint seeking = 0;
38 static gint seek_cnt = 0;
39 static gint seek_trips = 0;
40 
41 static gint preset_mode = FALSE;
42 static gint preset_mode_point = 0;
43 static gint preset_mode_seek = 0;
44 
45 static gint preset_seeking = 0;
46 
47 static gint preset_scan = FALSE;
48 static guint32 preset_frequency = 0;
49 static gint preset_muted = FALSE;
50 
51 static gint vol_btn_down = 0;
52 static gint bal_btn_down = 0;
53 
54 
55 static void auto_seek_reset(void);
56 
57 static void preset_seek_increment(gint direction_up);
58 static void preset_auto_scan_end(void);
59 
60 static void adjust_volume_by(gint n);
61 static void adjust_balance_by(gint n);
62 
63 
64 /*
65  *-----------------------------------------------------------------------------
66  * main loop!
67  *-----------------------------------------------------------------------------
68  */
69 
70 
main_loop(gpointer data)71 static gint main_loop(gpointer data)
72 {
73 	static gint status_cnt = 0;
74 	static gint flash = 0;
75 	static gint mixer_counter = 0;
76 
77 	flash++;
78 	if (flash > RADIO_STATUS_INTERVAL / 2) flash = 0;
79 
80 	if (vol_btn_down !=0) adjust_volume_by((vol_btn_down > 0) ? 3 : -3);
81 	if (bal_btn_down !=0) adjust_balance_by((bal_btn_down > 0) ? -3 : 3);
82 
83 	/* update mixer (volume/balance controls) every 4 seconds */
84 	mixer_counter++;
85 	if (mixer_counter > RADIO_STATUS_INTERVAL * 4)
86 		{
87 		mixer_counter = 0;
88 		display_set_volume();
89 		display_set_balance();
90 		}
91 
92 	if (preset_scan)
93 		{
94 		display_increment_scanner(FALSE);
95 		display_set_preset_scan(TRUE);
96 		if (flash == 0) display_update_preset(TRUE, -1);
97 
98 		if (frequency + RADIO_SCAN_INCREMENT > radio_limit_get_upper())
99 			{
100 			preset_auto_scan_end();
101 			}
102 		}
103 
104 	if (auto_seeking != 0)
105 		{
106 		if (!radio_status(&stereo, &signal_strength))
107 			{
108 			auto_seek_reset();
109 			}
110 		else if (auto_seek_signal < 0)
111 			{
112 			if (signal_strength < RADIO_SCAN_SENSITIVITY) auto_seek_signal = 0;
113 			seek_increment(RADIO_SCAN_INCREMENT, (auto_seeking > 0));
114 			display_increment_scanner(FALSE);
115 			}
116 		else if (auto_seek_signal == 0)
117 			{
118 			if (signal_strength >= RADIO_SCAN_SENSITIVITY)
119 				{
120 				auto_seek_signal = 1;
121 				auto_seek_freq = frequency;
122 				}
123 			seek_increment(RADIO_SCAN_INCREMENT, (auto_seeking > 0));
124 			display_increment_scanner(FALSE);
125 			}
126 		else
127 			{
128 			if (signal_strength < RADIO_SCAN_SENSITIVITY)
129 				{
130 				guint32 new_freq;
131 
132 				new_freq = (auto_seek_freq + (frequency - RADIO_SCAN_INCREMENT)) / 2;
133 				new_freq = radio_freq_clamp_to_increment(new_freq, freq_step);
134 
135 				if (debug_mode) printf("auto scan using %d\n", new_freq);
136 
137 				auto_seek_reset();
138 
139 				if (preset_scan)
140 					{
141 					gint p;
142 
143 					p = preset_list_find_free_slot();
144 					if (p >= 0)
145 						{
146 						preset_set(p, new_freq, NULL);
147 						display_preset_list_update(p);
148 						}
149 					if (debug_mode) printf("Auto seeked station %s as preset %d\n", radio_freq_to_text(new_freq), p);
150 
151 					auto_seeking = 1;
152 					}
153 				else
154 					{
155 					seek_to_freq(new_freq);
156 					mute_set(FALSE);
157 					}
158 				}
159 			else
160 				{
161 				seek_increment(RADIO_SCAN_INCREMENT, (auto_seeking > 0));
162 				display_increment_scanner(FALSE);
163 				}
164 			}
165 
166 		display_update_status();
167 		return TRUE;
168 		}
169 
170 	status_cnt++;
171 	if (status_cnt > RADIO_SCANS_PER_SECOND / RADIO_STATUS_INTERVAL)
172 		{
173 		if (radio_status(&stereo, &signal_strength))
174 			{
175 			display_update_status();
176 			}
177 
178 		status_cnt = 0;
179 		}
180 
181 	if (seeking != 0 || preset_mode_seek != 0 || preset_seeking != 0)
182 		{
183 		seek_cnt++;
184 		if (seek_cnt > RADIO_SCANS_PER_SECOND / RADIO_SLOW_SEEK)
185 			{
186 			seek_cnt = 0;
187 			if (seek_trips <= RADIO_SLOW_THRESHHOLD) seek_trips++;
188 			}
189 
190 		if (seek_cnt == 0 || seek_trips > RADIO_SLOW_THRESHHOLD)
191 			{
192 			if (preset_mode_seek != 0)
193 				{
194 				preset_seek_increment((preset_mode_seek > 0));
195 				flash = 1;
196 				}
197 			else if (seeking != 0)
198 				{
199 				seek_increment(freq_step, (seeking > 0));
200 				}
201 			else
202 				{
203 				if (preset_seeking > 0)
204 					{
205 					preset_next();
206 					}
207 				else
208 					{
209 					preset_prev();
210 					}
211 				}
212 			}
213 		}
214 	else
215 		{
216 		seek_trips = 0;
217 		seek_cnt = 0;
218 
219 		if (preset_mode && flash == 0)
220 			{
221 			display_update_preset(TRUE, preset_mode_point);
222 			}
223 		}
224 
225 	return TRUE;
226 }
227 
main_loop_init()228 void main_loop_init()
229 {
230 	if (main_loop_id == -1)
231 		{
232 		main_loop_id = g_timeout_add(1000 / RADIO_SCANS_PER_SECOND,
233 					     main_loop, NULL);
234 		}
235 }
236 
237 /*
238  *-----------------------------------------------------------------------------
239  * seek
240  *-----------------------------------------------------------------------------
241  */
242 
seek_to_freq(guint32 freq)243 void seek_to_freq(guint32 freq)
244 {
245 	gchar *buf;
246 	gchar *number;
247 	const gchar *desc;
248 
249 	CLAMP(freq, radio_limit_get_lower(), radio_limit_get_upper());
250 
251 	frequency = freq;
252 
253 	if (!muted) radio_set_mute(TRUE);
254 	radio_set_freq(frequency);
255 	if (!muted) radio_set_mute(FALSE);
256 
257 	if (preset < 0 || !preset_is_freq(preset, frequency))
258 		{
259 		preset = preset_find_freq(frequency);
260 		}
261 
262 	display_set_frequency(frequency);
263 	if (!preset_scan) display_update_preset(FALSE, -1);
264 
265 	number = radio_freq_to_text(frequency);
266 	desc = preset_get_description(preset);
267 	if (!desc)
268 		{
269 		buf = number;
270 		number = NULL;
271 		}
272 	else
273 		{
274 		buf = g_strdup_printf("%s %s", number, desc);
275 		}
276 	window_main_set_title(buf);
277 	g_free(buf);
278 	g_free(number);
279 }
280 
seek_increment(guint32 step,gint direction_up)281 void seek_increment(guint32 step, gint direction_up)
282 {
283 	guint32 old;
284 	guint32 l, h;
285 
286 	l = radio_limit_get_lower();
287 	h = radio_limit_get_upper();
288 
289 	/* sane steps */
290 	if (step < 10000) step = 10000;
291 
292 	old = frequency;
293 	frequency = radio_freq_clamp_to_increment(frequency, step);
294 
295 	if (direction_up)
296 		{
297 		if (frequency <= old) frequency += step;
298 		if (frequency > h) frequency = l;
299 		}
300 	else
301 		{
302 		if (frequency >= old) frequency -= step;
303 		if (frequency < l) frequency = h;
304 		}
305 
306 	seek_to_freq(frequency);
307 }
308 
seek_start(gint direction_up)309 void seek_start(gint direction_up)
310 {
311 	gint d;
312 
313 	if (preset_scan) return;
314 
315 	if (direction_up)
316 		{
317 		d = 1;
318 		}
319 	else
320 		{
321 		d = -1;
322 		}
323 	seek_cnt = 0;
324 	seek_trips = 0;
325 
326 	if (preset_mode)
327 		{
328 		preset_mode_seek = d;
329 		preset_seek_increment(preset_mode_seek > 0);
330 		return;
331 		}
332 
333 	if (seek_mode == SEEK_MODE_PRESET)
334 		{
335 		auto_seek_reset();
336 
337 		if (direction_up)
338 			{
339 			preset_next();
340 			}
341 		else
342 			{
343 			preset_prev();
344 			}
345 
346 		preset_seeking = d;
347 		return;
348 		}
349 
350 	if (seek_mode == SEEK_MODE_AUTO)
351 		{
352 		if (!auto_seek_nomute) mute_set(TRUE);
353 		seek_increment(RADIO_SCAN_INCREMENT, direction_up);
354 
355 		if (auto_seeking != 0)
356 			{
357 			if (auto_seeking == d)
358 				{
359 				auto_seeking = 0;
360 				mute_set(FALSE);
361 				}
362 			else
363 				{
364 				auto_seek_reset();
365 				auto_seeking = d;
366 				}
367 			}
368 		else
369 			{
370 			auto_seek_reset();
371 			auto_seeking = d;
372 			}
373 		return;
374 		}
375 
376 	/* SEEK_MODE_MANUAL */
377 
378 	auto_seek_reset();
379 	seek_increment(freq_step, direction_up);
380 	seeking = d;
381 }
382 
seek_start_by_mode(SeekMode mode,gint direction_up)383 void seek_start_by_mode(SeekMode mode, gint direction_up)
384 {
385 	SeekMode orig_mode;
386 
387 	orig_mode = seek_mode;
388 
389 	seek_mode = mode;
390 	seek_start(direction_up);
391 	seek_mode = orig_mode;
392 }
393 
seek_stop(void)394 void seek_stop(void)
395 {
396 	if (preset_scan) return;
397 
398 	seeking = 0;
399 	seek_cnt = 0;
400 	seek_trips = 0;
401 
402 	preset_mode_seek = 0;
403 	preset_seeking = 0;
404 }
405 
auto_seek_reset(void)406 static void auto_seek_reset(void)
407 {
408 	auto_seeking = 0;
409 	auto_seek_signal = -1;
410 	auto_seek_freq = 0;
411 	if (!preset_scan) display_increment_scanner(TRUE);
412 }
413 
414 /*
415  *-----------------------------------------------------------------------------
416  * modes, etc.
417  *-----------------------------------------------------------------------------
418  */
419 
mute_set(gint set)420 void mute_set(gint set)
421 {
422 	if (muted == set) return;
423 	if (preset_scan) return;
424 
425 	muted = set;
426 	radio_set_mute(muted);
427 	display_update_status();
428 }
429 
mute_toggle(void)430 void mute_toggle(void)
431 {
432 	mute_set(!muted);
433 }
434 
mode_set(SeekMode mode)435 void mode_set(SeekMode mode)
436 {
437 	if (preset_scan) return;
438 
439 	seek_mode = mode;
440 	display_set_mode(TRUE);
441 }
442 
mode_toggle(void)443 void mode_toggle(void)
444 {
445 	SeekMode mode;
446 
447 	if (seek_mode == SEEK_MODE_MANUAL)
448 		{
449 		mode = SEEK_MODE_PRESET;
450 		}
451 	else if (seek_mode == SEEK_MODE_PRESET)
452 		{
453 		mode = SEEK_MODE_AUTO;
454 		}
455 	else
456 		{
457 		mode = SEEK_MODE_MANUAL;
458 		}
459 
460 	mode_set(mode);
461 }
462 
463 /*
464  *-----------------------------------------------------------------------------
465  * presets, etc.
466  *-----------------------------------------------------------------------------
467  */
468 
preset_select(gint p)469 void preset_select(gint p)
470 {
471 	if (p < 0 || p >= PRESET_LIST_SIZE || preset == p) return;
472 
473 	if (preset_scan) return;
474 
475 	if (preset_mode)
476 		{
477 		preset_mode_point = p;
478 		preset_button_click();
479 		return;
480 		}
481 
482 	if (!preset_is_set(p)) return;
483 
484 	auto_seek_reset();
485 
486 	preset = p;
487 	seek_to_freq(preset_get_freq(p));
488 	mute_set(FALSE);
489 }
490 
preset_next(void)491 void preset_next(void)
492 {
493 	gint p, start_p;
494 
495 	if (preset_is_freq(preset, frequency))
496 		{
497 		p = preset + 1;
498 		}
499 	else
500 		{
501 		p = -1;
502 		}
503 
504 	start_p = p;
505 	if (p < 0) p = 0;
506 
507 	while (p < PRESET_LIST_SIZE && !preset_is_set(p)) p++;
508 
509 	if (p >= PRESET_LIST_SIZE && start_p >= 0)
510 		{
511 		p = 0;
512 		while (p < start_p && !preset_is_set(p)) p++;
513 		if (start_p == p) return;
514 		}
515 
516 	preset_select(p);
517 }
518 
preset_prev(void)519 void preset_prev(void)
520 {
521 	gint p, start_p;
522 
523 	if (preset_is_freq(preset, frequency))
524 		{
525 		p = preset - 1;
526 		}
527 	else
528 		{
529 		p = -1;
530 		}
531 
532 	start_p = p;
533 	if (p < 0) p = PRESET_LIST_SIZE - 1;
534 
535 	while (p >= 0 && !preset_is_set(p)) p--;
536 
537 	if (p < 0 && start_p >= 0)
538 		{
539 		p = PRESET_LIST_SIZE - 1;
540 		while (p > start_p && !preset_is_set(p)) p--;
541 		if (p < 0) return;
542 		}
543 
544 	preset_select(p);
545 }
546 
preset_seek_increment(gint direction_up)547 static void preset_seek_increment(gint direction_up)
548 {
549 	if (direction_up)
550 		{
551 		preset_mode_point++;
552 		if (preset_mode_point >= PRESET_LIST_SIZE) preset_mode_point = 0;
553 		}
554 	else
555 		{
556 		preset_mode_point--;
557 		if (preset_mode_point < 0) preset_mode_point = PRESET_LIST_SIZE - 1;
558 		}
559 
560 	display_update_preset(TRUE, preset_mode_point);
561 }
562 
preset_button_click(void)563 void preset_button_click(void)
564 {
565 	if (preset_scan) return;
566 
567 	if (preset_mode)
568 		{
569 		preset_mode = FALSE;
570 		preset_set(preset_mode_point, frequency, NULL);
571 		preset = preset_mode_point;
572 		display_preset_list_update(preset_mode_point);
573 		display_update_preset(FALSE, 0);
574 		}
575 	else
576 		{
577 		preset_mode = TRUE;
578 		display_update_preset(TRUE, preset_mode_point);
579 		display_set_description(_("Select preset"));
580 		}
581 }
582 
preset_cancel(void)583 void preset_cancel(void)
584 {
585 	if (preset_scan)
586 		{
587 		preset_auto_scan_end();
588 		}
589 	else if (preset_mode)
590 		{
591 		preset_mode = FALSE;
592 		display_update_preset(FALSE, preset);
593 		}
594 }
595 
preset_mode_get(void)596 gint preset_mode_get(void)
597 {
598 	return (preset_mode || preset_scan);
599 }
600 
preset_clear_one(gint p)601 void preset_clear_one(gint p)
602 {
603 	if (p < 0) return;
604 
605 	preset_clear(p);
606 
607 	if (preset == p) preset = -1;
608 	display_preset_list_update(p);
609 	display_update_preset(FALSE, preset);
610 }
611 
612 
613 static GenericDialog *preset_clear_dlg = NULL;
614 
615 
preset_clear_cancel_cb(GenericDialog * gd,gpointer data)616 static void preset_clear_cancel_cb(GenericDialog *gd, gpointer data)
617 {
618 	generic_dialog_close(gd);
619 	preset_clear_dlg = NULL;
620 }
621 
preset_clear_ok_cb(GenericDialog * gd,gpointer data)622 static void preset_clear_ok_cb(GenericDialog *gd, gpointer data)
623 {
624 	generic_dialog_close(gd);
625 	preset_clear_dlg = NULL;
626 
627 	preset_list_clear();
628 	preset = -1;
629 	display_preset_list_update(-1);
630 	display_update_preset(FALSE, preset);
631 }
632 
preset_clear_all(void)633 void preset_clear_all(void)
634 {
635 	if (preset_clear_dlg) return;
636 
637 	preset_clear_dlg = generic_dialog_new(_("Clear presets - GQradio"),
638 					      "GQradio", "preset_clear",
639 					      NULL, FALSE,
640 					      preset_clear_cancel_cb, NULL);
641 	generic_dialog_add_button(preset_clear_dlg, GTK_STOCK_CLEAR, NULL,
642 				  preset_clear_ok_cb, TRUE);
643 
644 	generic_dialog_add_message(preset_clear_dlg, GTK_STOCK_DIALOG_QUESTION,
645 				   _("Clear the preset list?"), NULL);
646 
647 	gtk_widget_show(preset_clear_dlg->dialog);
648 }
649 
preset_auto_scan_end(void)650 static void preset_auto_scan_end(void)
651 {
652 	auto_seek_reset();
653 
654 	preset_scan = FALSE;
655 	muted = preset_muted;
656 
657 	seek_to_freq(preset_frequency);
658 	display_set_preset_scan(FALSE);
659 	display_increment_scanner(TRUE);
660 }
661 
662 
663 static GenericDialog *preset_scan_dlg = NULL;
664 
665 
preset_scan_cancel_cb(GenericDialog * gd,gpointer data)666 static void preset_scan_cancel_cb(GenericDialog *gd, gpointer data)
667 {
668 	generic_dialog_close(gd);
669 	preset_scan_dlg = NULL;
670 }
671 
preset_scan_ok_cb(GenericDialog * gd,gpointer data)672 static void preset_scan_ok_cb(GenericDialog *gd, gpointer data)
673 {
674 	generic_dialog_close(gd);
675 	preset_scan_dlg = NULL;
676 
677 	if (!preset_scan)
678 		{
679 		preset_cancel();
680 
681 		preset_muted = muted;
682 		if (!auto_seek_nomute) mute_set(TRUE);
683 
684 		preset_scan = TRUE;
685 		preset_frequency = frequency;
686 
687 		seek_mode = SEEK_MODE_AUTO;
688 		auto_seek_reset();
689 		auto_seeking = 1;
690 
691 		display_set_mode(TRUE);
692 		seek_to_freq(radio_limit_get_lower());
693 		display_increment_scanner(FALSE);
694 		display_set_preset_scan(TRUE);
695 		}
696 }
697 
preset_auto_scan_click(void)698 void preset_auto_scan_click(void)
699 {
700 	if (preset_scan)
701 		{
702 		preset_auto_scan_end();
703 		}
704 	else if (!preset_scan_dlg)
705 		{
706 		preset_scan_dlg = generic_dialog_new(_("Auto Scan - GQradio"),
707 						     "GQradio", "preset_scan",
708 						     NULL, FALSE,
709 						     preset_scan_cancel_cb, NULL);
710 		generic_dialog_add_button(preset_scan_dlg, GTK_STOCK_FIND, _("Scan"),
711 					  preset_scan_ok_cb, TRUE);
712 
713 		generic_dialog_add_message(preset_scan_dlg, GTK_STOCK_DIALOG_QUESTION,
714 					   _("Scan frequencies to fill the preset list?"), NULL);
715 
716 		gtk_widget_show(preset_scan_dlg->dialog);
717 		}
718 }
719 
720 /*
721  *-----------------------------------------------------------------------------
722  * mixer, volume and balance
723  *-----------------------------------------------------------------------------
724  */
725 
adjust_volume_by(gint n)726 static void adjust_volume_by(gint n)
727 {
728 	gint vol = get_volume();
729 	vol += n;
730 	if (vol < 0) vol = 0;
731 	if (vol > 100) vol = 100;
732 	set_volume(vol);
733 	display_set_volume();
734 }
735 
volume_adjust(float pos)736 void volume_adjust(float pos)
737 {
738 	set_volume((gint)(pos * 100));
739 }
740 
btn_volume_up_pressed(void)741 void btn_volume_up_pressed(void)
742 {
743 	vol_btn_down = 1;
744 	adjust_volume_by(3);
745 }
746 
btn_volume_down_pressed(void)747 void btn_volume_down_pressed(void)
748 {
749 	vol_btn_down = -1;
750 	adjust_volume_by(-3);
751 }
752 
btn_volume_released(void)753 void btn_volume_released(void)
754 {
755 	vol_btn_down = 0;
756 }
757 
758 /*
759  *-----------------------------------------------------------------------------
760  * balance callbacks
761  *-----------------------------------------------------------------------------
762  */
763 
adjust_balance_by(gint n)764 static void adjust_balance_by(gint n)
765 {
766 	gint bal = get_balance();
767 	bal += n;
768 	if (bal < 0) bal = 0;
769 	if (bal > 100) bal = 100;
770 	if (bal > 50 - abs(n) && bal < 50 + abs(n)) bal = 50; /* basic balance auto-centering */
771 	set_balance(bal);
772 	display_set_balance();
773 }
774 
balance_adjust(float pos)775 void balance_adjust(float pos)
776 {
777 	gint p = pos * 100;
778 	if (p > 44 && p < 56) p = 50; /* to help balance 'lock' on center */
779 	set_balance(p);
780 }
781 
btn_balance_left_pressed(void)782 void btn_balance_left_pressed(void)
783 {
784 	bal_btn_down = 1;
785 	adjust_balance_by(-3);
786 }
787 
btn_balance_right_pressed(void)788 void btn_balance_right_pressed(void)
789 {
790 	bal_btn_down = -1;
791 	adjust_balance_by(3);
792 }
793 
btn_balance_released(void)794 void btn_balance_released(void)
795 {
796 	bal_btn_down = 0;
797 }
798 
mixer_run(void)799 void mixer_run(void)
800 {
801 	if (mixer_command)
802 		{
803 		gchar *command = g_strconcat(mixer_command, " &", NULL);
804 		system(command);
805 		g_free(command);
806 		}
807 }
808 
809 
810 
811 
812 
813