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