summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Nielsen Feltzing <linus@haxx.se>2002-09-27 09:31:31 +0000
committerLinus Nielsen Feltzing <linus@haxx.se>2002-09-27 09:31:31 +0000
commitbb572c44121e48d9d54411dff9e0f8dce015e550 (patch)
treea91d8c8e9e5675c9b5039ddc8108f81f55fc4f49
parentacfacd938cfa878aeb69410532b2de58698f703a (diff)
downloadrockbox-bb572c44121e48d9d54411dff9e0f8dce015e550.tar.gz
rockbox-bb572c44121e48d9d54411dff9e0f8dce015e550.zip
Philip Pertermanns peak meter
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@2436 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/lang/english.lang30
-rw-r--r--apps/settings.c27
-rw-r--r--apps/settings.h4
-rw-r--r--apps/settings_menu.c66
-rw-r--r--apps/wps-display.c53
-rw-r--r--apps/wps.c24
-rw-r--r--docs/CUSTOM_WPS_FORMAT2
-rw-r--r--firmware/drivers/mas.h2
-rw-r--r--uisimulator/win32/Makefile5
-rw-r--r--uisimulator/x11/Makefile5
10 files changed, 212 insertions, 6 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 83ccf037da..afea869bee 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -834,3 +834,33 @@ id: LANG_SET_BOOL_NO
834desc: bool false representation 834desc: bool false representation
835eng: "No" 835eng: "No"
836new: 836new:
837
838id: LANG_PM_MENU
839desc: in the display menu
840eng: "Peak meter"
841new:
842
843id: LANG_PM_RELEASE
844desc: in the peak meter menu
845eng: "Peak release"
846new:
847
848id: LANG_PM_PEAK_HOLD
849desc: in the peak meter menu
850eng: "Peak hold time"
851new:
852
853id: LANG_PM_CLIP_HOLD
854desc: in the peak meter menu
855eng: "Clip hold time"
856new:
857
858id: LANG_PM_ETERNAL
859desc: in the peak meter menu
860eng: "eternal"
861new:
862
863id: LANG_PM_UNITS_PER_READ
864desc: in the peak meter menu
865eng: "Units per read"
866new:
diff --git a/apps/settings.c b/apps/settings.c
index 31d4f1a82b..1b4f864ec5 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -53,6 +53,12 @@ char rockboxdir[] = ROCKBOX_DIR; /* config/font/data file directory */
53#define CONFIG_BLOCK_SIZE 512 53#define CONFIG_BLOCK_SIZE 512
54#define RTC_BLOCK_SIZE 44 54#define RTC_BLOCK_SIZE 44
55 55
56#ifdef HAVE_LCD_BITMAP
57#define MAX_LINES 10
58#else
59#define MAX_LINES 2
60#endif
61
56/******************************************** 62/********************************************
57 63
58Config block as saved on the battery-packed RTC user RAM memory block 64Config block as saved on the battery-packed RTC user RAM memory block
@@ -80,6 +86,9 @@ offset abs
800x16 0x2a <(int) Byte offset into resume file> 860x16 0x2a <(int) Byte offset into resume file>
810x1a 0x2e <time until disk spindown> 870x1a 0x2e <time until disk spindown>
820x1b 0x2f <browse current, play selected> 880x1b 0x2f <browse current, play selected>
890x1c 0x30 <peak meter hold timeout (bit 0-4)>
900x1d 0x31 <peak meter clip hold timeout (bit 0-4)>
910x1e 0x32 <peak meter release step size>
83 92
84 <all unused space filled with 0xff> 93 <all unused space filled with 0xff>
85 94
@@ -290,6 +299,10 @@ int settings_save( void )
290 (((global_settings.browse_current & 1)) | 299 (((global_settings.browse_current & 1)) |
291 ((global_settings.play_selected & 1) << 1)); 300 ((global_settings.play_selected & 1) << 1));
292 301
302 config_block[0x1c] = (unsigned char)global_settings.peak_meter_hold;
303 config_block[0x1d] = (unsigned char)global_settings.peak_meter_clip_hold;
304 config_block[0x1e] = (unsigned char)global_settings.peak_meter_release;
305
293 memcpy(&config_block[0xF8], &global_settings.resume_seed, 4); 306 memcpy(&config_block[0xF8], &global_settings.resume_seed, 4);
294 307
295 memcpy(&config_block[0x24], &global_settings.total_uptime, 4); 308 memcpy(&config_block[0x24], &global_settings.total_uptime, 4);
@@ -400,6 +413,15 @@ void settings_load(void)
400 global_settings.play_selected = (config_block[0x1b] >> 1) & 1; 413 global_settings.play_selected = (config_block[0x1b] >> 1) & 1;
401 } 414 }
402 415
416 if (config_block[0x1c] != 0xFF)
417 global_settings.peak_meter_hold = (config_block[0x1c]) & 0x1f;
418
419 if (config_block[0x1d] != 0xFF)
420 global_settings.peak_meter_clip_hold = (config_block[0x1d]) & 0x1f;
421
422 if (config_block[0x1e] != 0xFF)
423 global_settings.peak_meter_release = config_block[0x1e];
424
403 memcpy(&global_settings.resume_seed, &config_block[0xF8], 4); 425 memcpy(&global_settings.resume_seed, &config_block[0xF8], 4);
404 426
405 if (config_block[0x24] != 0xFF) 427 if (config_block[0x24] != 0xFF)
@@ -471,7 +493,7 @@ bool settings_load_eq(char* file)
471 break; 493 break;
472 case 3: 494 case 3:
473 snprintf(buf_disp,sizeof(buf_disp),"[%s]%s", buf_set, buf_val); 495 snprintf(buf_disp,sizeof(buf_disp),"[%s]%s", buf_set, buf_val);
474 lcd_puts(0,line++ % 6,buf_disp); 496 lcd_puts(0,line++ % MAX_LINES, buf_disp);
475 lcd_update(); 497 lcd_update();
476 sleep(HZ/2); 498 sleep(HZ/2);
477 if (!strcasecmp(buf_set,"volume")) { 499 if (!strcasecmp(buf_set,"volume")) {
@@ -610,6 +632,9 @@ void settings_reset(void) {
610 global_settings.disk_spindown = 5; 632 global_settings.disk_spindown = 5;
611 global_settings.browse_current = false; 633 global_settings.browse_current = false;
612 global_settings.play_selected = true; 634 global_settings.play_selected = true;
635 global_settings.peak_meter_release = 8;
636 global_settings.peak_meter_hold = 1;
637 global_settings.peak_meter_clip_hold = 16;
613} 638}
614 639
615 640
diff --git a/apps/settings.h b/apps/settings.h
index 048c673539..bbc7bb3dcc 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -86,6 +86,10 @@ struct user_settings
86 int ff_rewind_accel; /* FF/Rewind acceleration (in seconds per doubling) */ 86 int ff_rewind_accel; /* FF/Rewind acceleration (in seconds per doubling) */
87 int disk_spindown; /* time until disk spindown, in seconds (0=off) */ 87 int disk_spindown; /* time until disk spindown, in seconds (0=off) */
88 88
89 int peak_meter_release; /* units per read out */
90 int peak_meter_hold; /* hold time for peak meter in 1/100 s */
91 int peak_meter_clip_hold; /* hold time for clips */
92
89 /* show status bar */ 93 /* show status bar */
90 bool statusbar; /* 0=hide, 1=show */ 94 bool statusbar; /* 0=hide, 1=show */
91 95
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 8aba4bc2f2..643f5be542 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -36,6 +36,7 @@
36#include "powermgmt.h" 36#include "powermgmt.h"
37#include "rtc.h" 37#include "rtc.h"
38#include "ata.h" 38#include "ata.h"
39#include "peakmeter.h"
39#include "lang.h" 40#include "lang.h"
40 41
41static bool contrast(void) 42static bool contrast(void)
@@ -44,6 +45,68 @@ static bool contrast(void)
44 lcd_set_contrast, 1, 0, MAX_CONTRAST_SETTING ); 45 lcd_set_contrast, 1, 0, MAX_CONTRAST_SETTING );
45} 46}
46 47
48#ifdef HAVE_LCD_BITMAP
49/**
50 * Menu to set the hold time of normal peaks.
51 */
52static bool peak_meter_hold(void) {
53 char* names[] = { str(LANG_OFF),
54 "200 ms ", "300 ms ", "500 ms ", "1 s ", "2 s ",
55 "3 s ", "4 s ", "5 s ", "6 s ", "7 s",
56 "8 s", "9 s", "10 s", "15 s", "20 s",
57 "30 s", "1 min"
58 };
59 return set_option( str(LANG_PM_PEAK_HOLD),
60 &global_settings.peak_meter_hold, names,
61 18, NULL);
62}
63
64/**
65 * Menu to set the hold time of clips.
66 */
67static bool peak_meter_clip_hold(void) {
68 char* names[] = { str(LANG_PM_ETERNAL),
69 "1s ", "2s ", "3s ", "4s ", "5s ",
70 "6s ", "7s ", "8s ", "9s ", "10s",
71 "15s", "20s", "25s", "30s", "45s",
72 "60s", "90s", "2min", "3min", "5min",
73 "10min", "20min", "45min", "90min"
74 };
75 return set_option( str(LANG_PM_CLIP_HOLD),
76 &global_settings.peak_meter_clip_hold, names,
77 25, peak_meter_set_clip_hold);
78}
79
80/**
81 * Menu to set the release time of the peak meter.
82 */
83static bool peak_meter_release(void) {
84 return set_int( str(LANG_PM_RELEASE), str(LANG_PM_UNITS_PER_READ),
85 &global_settings.peak_meter_release,
86 NULL, 1, 1, LCD_WIDTH);
87}
88
89/**
90 * Menu to configure the peak meter
91 */
92static bool peak_meter_menu(void)
93{
94 int m;
95 bool result;
96
97 struct menu_items items[] = {
98 { str(LANG_PM_RELEASE) , peak_meter_release },
99 { str(LANG_PM_PEAK_HOLD), peak_meter_hold },
100 { str(LANG_PM_CLIP_HOLD), peak_meter_clip_hold },
101 };
102
103 m=menu_init( items, sizeof items / sizeof(struct menu_items) );
104 result = menu_run(m);
105 menu_exit(m);
106 return result;
107}
108#endif
109
47#ifndef HAVE_RECORDER_KEYPAD 110#ifndef HAVE_RECORDER_KEYPAD
48static bool shuffle(void) 111static bool shuffle(void)
49{ 112{
@@ -313,6 +376,9 @@ static bool display_settings_menu(void)
313 { str(LANG_SCROLL_MENU), scroll_speed }, 376 { str(LANG_SCROLL_MENU), scroll_speed },
314 { str(LANG_BACKLIGHT), backlight_timer }, 377 { str(LANG_BACKLIGHT), backlight_timer },
315 { str(LANG_CONTRAST), contrast }, 378 { str(LANG_CONTRAST), contrast },
379#ifdef HAVE_LCD_BITMAP
380 { str(LANG_PM_MENU), peak_meter_menu },
381#endif
316 }; 382 };
317 383
318 m=menu_init( items, sizeof items / sizeof(struct menu_items) ); 384 m=menu_init( items, sizeof items / sizeof(struct menu_items) );
diff --git a/apps/wps-display.c b/apps/wps-display.c
index ec1e9c76e5..a8980855e4 100644
--- a/apps/wps-display.c
+++ b/apps/wps-display.c
@@ -37,10 +37,13 @@
37#include "status.h" 37#include "status.h"
38#include "wps-display.h" 38#include "wps-display.h"
39#include "debug.h" 39#include "debug.h"
40#include "mas.h"
40#include "lang.h" 41#include "lang.h"
42
41#ifdef HAVE_LCD_BITMAP 43#ifdef HAVE_LCD_BITMAP
42#include "icons.h" 44#include "icons.h"
43#include "widgets.h" 45#include "widgets.h"
46#include "peakmeter.h"
44#endif 47#endif
45 48
46#define WPS_CONFIG ROCKBOX_DIR "/default.wps" 49#define WPS_CONFIG ROCKBOX_DIR "/default.wps"
@@ -52,12 +55,12 @@
52#endif 55#endif
53 56
54#define FORMAT_BUFFER_SIZE 300 57#define FORMAT_BUFFER_SIZE 300
55
56struct format_flags 58struct format_flags
57{ 59{
58 bool dynamic; 60 bool dynamic;
59 bool scroll; 61 bool scroll;
60 bool player_progress; 62 bool player_progress;
63 bool peak_meter;
61}; 64};
62 65
63static char format_buffer[FORMAT_BUFFER_SIZE]; 66static char format_buffer[FORMAT_BUFFER_SIZE];
@@ -331,6 +334,13 @@ static char* get_tag(struct mp3entry* id3,
331 case 't': /* Total Time */ 334 case 't': /* Total Time */
332 format_time(buf, buf_size, id3->length); 335 format_time(buf, buf_size, id3->length);
333 return buf; 336 return buf;
337
338#ifdef HAVE_LCD_BITMAP
339 case 'm': /* Peak Meter */
340 flags->peak_meter = true;
341 flags->dynamic = true;
342 return "\x01";
343#endif
334 } 344 }
335 break; 345 break;
336 346
@@ -518,6 +528,15 @@ bool wps_refresh(struct mp3entry* id3, int ffwd_offset, bool refresh_all)
518 bool scroll_active = false; 528 bool scroll_active = false;
519 int i; 529 int i;
520 530
531 /* to find out wether the peak meter is enabled we
532 assume it wasn't until we find a line that contains
533 the peak meter. We can't use peak_meter_enabled itself
534 because that would mean to turn off the meter thread
535 temporarily. (That shouldn't matter unless yield
536 or sleep is called but who knows...)
537 */
538 bool enable_pm = false;
539
521 if (!id3) 540 if (!id3)
522 { 541 {
523 lcd_stop_scroll(); 542 lcd_stop_scroll();
@@ -537,6 +556,7 @@ bool wps_refresh(struct mp3entry* id3, int ffwd_offset, bool refresh_all)
537 flags.dynamic = false; 556 flags.dynamic = false;
538 flags.scroll = false; 557 flags.scroll = false;
539 flags.player_progress = false; 558 flags.player_progress = false;
559 flags.peak_meter = false;
540 format_display(buf, sizeof(buf), id3, format_lines[i], &flags); 560 format_display(buf, sizeof(buf), id3, format_lines[i], &flags);
541 dynamic_lines[i] = flags.dynamic; 561 dynamic_lines[i] = flags.dynamic;
542 562
@@ -556,6 +576,30 @@ bool wps_refresh(struct mp3entry* id3, int ffwd_offset, bool refresh_all)
556#endif 576#endif
557 } 577 }
558 578
579#ifdef HAVE_LCD_BITMAP
580 if (flags.peak_meter) {
581 int peak_meter_y;
582 int w,h;
583 int offset = global_settings.statusbar ? STATUSBAR_HEIGHT : 0;
584 lcd_getstringsize("M",&w,&h);
585
586 peak_meter_y = i * h + offset;
587
588 /* The user might decide to have the peak meter in the last
589 line so that it is only displayed if no status bar is
590 visible. If so we neither want do draw nor enable the
591 peak meter. */
592 if (peak_meter_y + h <= LCD_HEIGHT) {
593 /* found a line with a peak meter -> remember that we must
594 enable it later */
595 enable_pm = true;
596 peak_meter_draw(0, peak_meter_y, LCD_WIDTH,
597 MIN(h, LCD_HEIGHT - peak_meter_y));
598 }
599 continue;
600 }
601#endif
602
559 if (!scroll_active && flags.scroll && !flags.dynamic) 603 if (!scroll_active && flags.scroll && !flags.dynamic)
560 { 604 {
561 scroll_active = true; 605 scroll_active = true;
@@ -567,6 +611,10 @@ bool wps_refresh(struct mp3entry* id3, int ffwd_offset, bool refresh_all)
567 } 611 }
568 } 612 }
569 } 613 }
614
615 /* Now we know wether the peak meter is used.
616 So we can enable / disable the peak meter thread */
617 peak_meter_enabled = enable_pm;
570 lcd_update(); 618 lcd_update();
571 619
572 return true; 620 return true;
@@ -602,7 +650,8 @@ void wps_display(struct mp3entry* id3)
602 "%ia\n" 650 "%ia\n"
603 "%fb kbit %fv\n" 651 "%fb kbit %fv\n"
604 "Time: %pc / %pt\n" 652 "Time: %pc / %pt\n"
605 "%pb\n"); 653 "%pb\n"
654 "%pm\n");
606#else 655#else
607 wps_format("%s%pp/%pe: %?ia<%ia - >%?it<%it|%fm>\n" 656 wps_format("%s%pp/%pe: %?ia<%ia - >%?it<%it|%fm>\n"
608 "%pc/%pt\n"); 657 "%pc/%pt\n");
diff --git a/apps/wps.c b/apps/wps.c
index 2729b288f3..db4459c465 100644
--- a/apps/wps.c
+++ b/apps/wps.c
@@ -40,6 +40,7 @@
40#include "screens.h" 40#include "screens.h"
41#ifdef HAVE_LCD_BITMAP 41#ifdef HAVE_LCD_BITMAP
42#include "icons.h" 42#include "icons.h"
43#include "peakmeter.h"
43#endif 44#endif
44#include "lang.h" 45#include "lang.h"
45#define FF_REWIND_MAX_PERCENT 3 /* cap ff/rewind step size at max % of file */ 46#define FF_REWIND_MAX_PERCENT 3 /* cap ff/rewind step size at max % of file */
@@ -610,7 +611,7 @@ static bool menu(void)
610/* demonstrates showing different formats from playtune */ 611/* demonstrates showing different formats from playtune */
611int wps_show(void) 612int wps_show(void)
612{ 613{
613 int button, lastbutton = 0; 614 int button = 0, lastbutton = 0;
614 int old_repeat_mask; 615 int old_repeat_mask;
615 bool ignore_keyup = true; 616 bool ignore_keyup = true;
616 bool restore = false; 617 bool restore = false;
@@ -644,7 +645,27 @@ int wps_show(void)
644 645
645 while ( 1 ) 646 while ( 1 )
646 { 647 {
648
649#ifdef HAVE_LCD_BITMAP
650 /* when the peak meter is enabled we want to have a
651 few extra updates to make it look smooth. On the
652 other hand we don't want to waste energy if it
653 isn't displayed */
654 if (peak_meter_enabled) {
655 int i;
656 for (i = 0; i < 4; i++) {
657 button = button_get_w_tmo(HZ / 20);
658 if (button != 0) {
659 break;
660 }
661 wps_refresh(id3, 0, false);
662 }
663 } else {
664 button = button_get_w_tmo(HZ/5);
665 }
666#else
647 button = button_get_w_tmo(HZ/5); 667 button = button_get_w_tmo(HZ/5);
668#endif
648 669
649 /* discard first event if it's a button release */ 670 /* discard first event if it's a button release */
650 if (button && ignore_keyup) 671 if (button && ignore_keyup)
@@ -839,4 +860,5 @@ int wps_show(void)
839 if(button != BUTTON_NONE) 860 if(button != BUTTON_NONE)
840 lastbutton = button; 861 lastbutton = button;
841 } 862 }
863 return 0; /* unreachable - just to reduce compiler warnings */
842} 864}
diff --git a/docs/CUSTOM_WPS_FORMAT b/docs/CUSTOM_WPS_FORMAT
index 5162d2ea94..cecb4af169 100644
--- a/docs/CUSTOM_WPS_FORMAT
+++ b/docs/CUSTOM_WPS_FORMAT
@@ -46,6 +46,8 @@ Playlist/Song Info Tags:
46 Player: This will display a 1 character "cup" that empties as the 46 Player: This will display a 1 character "cup" that empties as the
47 progresses. 47 progresses.
48 Recorder: This will replace the entire line with a progress bar. 48 Recorder: This will replace the entire line with a progress bar.
49 %pm : Peak Meter (Recorder only)
50 The entire line is used as volume peak meter.
49 %pp : Playlist Position 51 %pp : Playlist Position
50 %pe : Total Number of Playlist Entries 52 %pe : Total Number of Playlist Entries
51 %pc : Current Time In Song 53 %pc : Current Time In Song
diff --git a/firmware/drivers/mas.h b/firmware/drivers/mas.h
index 5ccffdfd5b..71604fb136 100644
--- a/firmware/drivers/mas.h
+++ b/firmware/drivers/mas.h
@@ -22,6 +22,8 @@
22#define MAS_BANK_D0 0 22#define MAS_BANK_D0 0
23#define MAS_BANK_D1 1 23#define MAS_BANK_D1 1
24 24
25#define MAX_PEAK 0x8000
26
25/* 27/*
26 MAS I2C defs 28 MAS I2C defs
27*/ 29*/
diff --git a/uisimulator/win32/Makefile b/uisimulator/win32/Makefile
index 28e0eea16c..aa4136c5d6 100644
--- a/uisimulator/win32/Makefile
+++ b/uisimulator/win32/Makefile
@@ -67,7 +67,7 @@ FIRMSRCS = lcd-recorder.c power.c sprintf.c id3.c usb.c \
67 67
68APPS = main.c tree.c menu.c credits.c main_menu.c icons.c language.c \ 68APPS = main.c tree.c menu.c credits.c main_menu.c icons.c language.c \
69 playlist.c showtext.c wps.c wps-display.c settings.c status.c \ 69 playlist.c showtext.c wps.c wps-display.c settings.c status.c \
70 screens.c 70 screens.c peakmeter.c
71 71
72MENUS = games_menu.c demo_menu.c settings_menu.c sound_menu.c 72MENUS = games_menu.c demo_menu.c settings_menu.c sound_menu.c
73 73
@@ -203,6 +203,9 @@ $(OBJDIR)/status.o: $(APPDIR)/status.c
203$(OBJDIR)/screens.o: $(APPDIR)/screens.c 203$(OBJDIR)/screens.o: $(APPDIR)/screens.c
204 $(CC) $(APPCFLAGS) -c $< -o $@ 204 $(CC) $(APPCFLAGS) -c $< -o $@
205 205
206$(OBJDIR)/peakmeter.o: $(RECDIR)/peakmeter.c
207 $(CC) $(APPCFLAGS) -c $< -o $@
208
206$(OBJDIR)/version.o: $(FIRMWAREDIR)/version.c 209$(OBJDIR)/version.o: $(FIRMWAREDIR)/version.c
207 $(CC) $(CFLAGS) -c $< -o $@ 210 $(CC) $(CFLAGS) -c $< -o $@
208 211
diff --git a/uisimulator/x11/Makefile b/uisimulator/x11/Makefile
index 074b7f02ac..c3bb4e6ffe 100644
--- a/uisimulator/x11/Makefile
+++ b/uisimulator/x11/Makefile
@@ -82,7 +82,7 @@ FIRMSRCS = lcd-recorder.c sprintf.c id3.c debug.c usb.c mpeg.c power.c\
82 82
83APPS = main.c tree.c menu.c credits.c main_menu.c language.c\ 83APPS = main.c tree.c menu.c credits.c main_menu.c language.c\
84 playlist.c showtext.c wps.c wps-display.c settings.c status.c icons.c\ 84 playlist.c showtext.c wps.c wps-display.c settings.c status.c icons.c\
85 screens.c 85 screens.c peakmeter.c
86 86
87MENUS = games_menu.c demo_menu.c settings_menu.c sound_menu.c 87MENUS = games_menu.c demo_menu.c settings_menu.c sound_menu.c
88 88
@@ -242,6 +242,9 @@ $(OBJDIR)/status.o: $(APPDIR)/status.c
242$(OBJDIR)/screens.o: $(APPDIR)/screens.c 242$(OBJDIR)/screens.o: $(APPDIR)/screens.c
243 $(CC) $(APPCFLAGS) -c $< -o $@ 243 $(CC) $(APPCFLAGS) -c $< -o $@
244 244
245$(OBJDIR)/peakmeter.o: $(RECDIR)/peakmeter.c
246 $(CC) $(APPCFLAGS) -c $< -o $@
247
245$(OBJDIR)/id3.o: $(FIRMWAREDIR)/id3.c 248$(OBJDIR)/id3.o: $(FIRMWAREDIR)/id3.c
246 $(CC) $(APPCFLAGS) -c $< -o $@ 249 $(CC) $(APPCFLAGS) -c $< -o $@
247 250