/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2002 Philipp Pertermann * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include #include "sprintf.h" #include "system.h" #include "kernel.h" #include "spliteditor.h" #include "mpeg.h" #include "lcd.h" #include "button.h" #include "mas.h" #include "id3.h" #include "key_scheme.h" #define OSCI_HEIGHT (LCD_HEIGHT -16) static struct mp3entry* id3 = NULL; static unsigned int range_start = 0; static unsigned int range_end = 0; static unsigned int play_start = 0; static unsigned int play_end = 0; static int split_x = LCD_WIDTH / 2; static unsigned char osci_buffer[LCD_WIDTH]; static bool osci_valid = false; static unsigned int validation_start = ~(unsigned int)0; static int loop_mode = 0; static bool quit_requested = false; #define LOOP_MODE_ALL 0 #define LOOP_MODE_FROM 1 #define LOOP_MODE_TO 2 #define MIN_RANGE_SIZE 1000 /* Format time into buf. * * buf - buffer to format to. * buf_size - size of buffer. * time - time to format, in milliseconds. */ static void format_time_ms(char* buf, int buf_size, int time) { snprintf(buf, buf_size, "%d:%02d:%03d", time / 60000, time % 60000 / 1000, (time % 60000) % 1000); } static int xpos_to_time(int xpos) { int retval = 0; int range = range_end - range_start; retval = range_start + ((xpos * range) / LCD_WIDTH); return retval; } static int time_to_xpos(int time) { int retval = 0; int range = range_end - range_start; retval = ((time - range_start) * LCD_WIDTH) / range ; return retval; } static void update_data(void) { char buf[20]; lcd_clearrect(0, 0, LCD_WIDTH, LCD_HEIGHT - OSCI_HEIGHT); /* range length */ format_time_ms(buf, sizeof buf, range_end - range_start); lcd_puts(0, 0, buf); #if 0 /* osci valid */ if (osci_valid) { lcd_putsxy(0, 8, "valid"); } else { lcd_putsxy(0, 8, "invalid"); } format_time_ms(buf, sizeof buf, validation_start); lcd_getstringsize(buf, &width, &height); lcd_putsxy(24, 8, buf); #endif /* split point */ lcd_puts(0, 1, "Split at:"); format_time_ms(buf, sizeof buf, xpos_to_time(split_x)); lcd_puts(10, 1, buf); lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT - OSCI_HEIGHT); } static void invalidate_osci(void) { osci_valid = false; validation_start = ~(unsigned int)0; } int get_loop_mode(void){ return loop_mode; } void set_loop_mode(int mode) { /* range restriction */ loop_mode = mode % (LOOP_MODE_TO + 1); switch (loop_mode) { case LOOP_MODE_ALL: play_start = range_start; play_end = range_end; break; case LOOP_MODE_FROM: play_start = xpos_to_time(split_x); play_end = range_end; break; case LOOP_MODE_TO: play_start = range_start; play_end = xpos_to_time(split_x); break; } } static void redraw_osci(void) { int x; for (x = 0; x < LCD_WIDTH; x++) { if (osci_buffer[x] > 0) { lcd_drawline(x, LCD_HEIGHT - 1, x, LCD_HEIGHT - osci_buffer[x]); } } lcd_invertrect(split_x, LCD_HEIGHT - OSCI_HEIGHT, 1, OSCI_HEIGHT); } /* static void update_osci(void) { lcd_clearrect(0, LCD_HEIGHT - OSCI_HEIGHT, LCD_WIDTH, OSCI_HEIGHT); redraw_osci(); lcd_update_rect(0, LCD_HEIGHT - OSCI_HEIGHT, LCD_WIDTH, OSCI_HEIGHT); } */ static void set_range(unsigned int split_time, unsigned int range) { if (id3 != NULL) { if (range < MIN_RANGE_SIZE) { range = MIN_RANGE_SIZE; } range_start = (split_time > range / 2) ? (split_time - range / 2) : 0; range_end = MIN(range_start + range, id3->length); split_x = time_to_xpos(split_time); invalidate_osci(); set_loop_mode(LOOP_MODE_ALL); update_data(); } } static void zoom(int counter, int denominator) { unsigned char oldbuf[LCD_WIDTH]; int oldrange = range_end - range_start; int range = oldrange * counter / denominator; int i; int oldindex; int oldsplitx; int splitx; unsigned int split; memcpy(&oldbuf, &osci_buffer, LCD_WIDTH); oldsplitx = split_x; split = xpos_to_time(split_x); set_range(split, range); range = range_end - range_start; splitx = time_to_xpos(split); for (i = 0; i < LCD_WIDTH; i++) { oldindex = (i - splitx) * range / oldrange + oldsplitx ; if (oldindex >= 0 && oldindex < LCD_WIDTH) { osci_buffer[i] = oldbuf[oldindex]; } else { osci_buffer[i] = 0; } } split_x = time_to_xpos(split); redraw_osci(); invalidate_osci(); } int get_split_x(void){ return split_x; } void set_split_x(int newx) { lcd_invertrect (split_x, LCD_HEIGHT - OSCI_HEIGHT, 1, OSCI_HEIGHT); lcd_update_rect(split_x, LCD_HEIGHT - OSCI_HEIGHT, 1, OSCI_HEIGHT); if (newx >= 0 && newx < LCD_WIDTH) { split_x = newx; set_loop_mode(loop_mode); update_data(); } lcd_invertrect (split_x, LCD_HEIGHT - OSCI_HEIGHT, 1, OSCI_HEIGHT); lcd_update_rect(split_x, LCD_HEIGHT - OSCI_HEIGHT, 1, OSCI_HEIGHT); } void split_zoom_in(void) { lcd_clearrect(0, LCD_HEIGHT - OSCI_HEIGHT, LCD_WIDTH, OSCI_HEIGHT); zoom(3, 4); lcd_update_rect(0, LCD_HEIGHT - OSCI_HEIGHT, LCD_WIDTH, OSCI_HEIGHT); update_data(); } void split_zoom_out(void){ lcd_clearrect(0, LCD_HEIGHT - OSCI_HEIGHT, LCD_WIDTH, OSCI_HEIGHT); zoom(4, 3); lcd_update_rect(0, LCD_HEIGHT - OSCI_HEIGHT, LCD_WIDTH, OSCI_HEIGHT); update_data(); } void split_quit(void) { quit_requested = true; } unsigned int split_editor(struct mp3entry * id3_to_split, unsigned int split_time, unsigned int range) { int button = BUTTON_NONE; // bool paused = false; // int pitch = 100; id3 = id3_to_split; unsigned int last_elapsed = 0; int lastx = LCD_WIDTH -1; if (id3 != NULL) { set_range(split_time, range); quit_requested = false; while (!quit_requested) { /* get position */ unsigned int elapsed = id3->elapsed; int x = time_to_xpos(elapsed); /* are we still in the zoomed range? */ if (elapsed > play_start && elapsed < play_end) { /* read volume info */ unsigned short volume = mas_codec_readreg(MAS_REG_DQPEAK_L); volume += mas_codec_readreg(MAS_REG_DQPEAK_R); volume = (volume * OSCI_HEIGHT) / (2 * MAX_PEAK); /* update osci_buffer */ if (osci_valid || lastx == x) { osci_buffer[x] = MAX(osci_buffer[x], volume); } else { osci_buffer[x] = volume; } /* make room */ lcd_clearrect(x, LCD_HEIGHT - OSCI_HEIGHT, 1, OSCI_HEIGHT); /* draw a value */ if (osci_buffer[x] > 0) { lcd_drawline (x, LCD_HEIGHT - 1, x, LCD_HEIGHT - osci_buffer[x]); } /* mark the split point */ if (x == split_x) { lcd_invertrect(split_x, LCD_HEIGHT - OSCI_HEIGHT, 1, OSCI_HEIGHT); } /* mark the current position */ lcd_invertrect(x, LCD_HEIGHT - OSCI_HEIGHT, 1, OSCI_HEIGHT); if (lastx != x) { lcd_invertrect(lastx, LCD_HEIGHT - OSCI_HEIGHT, 1, OSCI_HEIGHT); } /* make visible */ lcd_update_rect(x, LCD_HEIGHT - OSCI_HEIGHT, 1, OSCI_HEIGHT); lcd_update_rect(lastx, LCD_HEIGHT - OSCI_HEIGHT, 1, OSCI_HEIGHT); lastx = x; } /* we're not in the zoom range -> rewind */ else { if (elapsed >= play_end) { switch (loop_mode) { case LOOP_MODE_ALL: case LOOP_MODE_TO: mpeg_ff_rewind(-(elapsed - range_start)); break; case LOOP_MODE_FROM: mpeg_ff_rewind(-(elapsed - xpos_to_time(split_x))); break; } } } button = button_get(false); yield(); key_scheme_current = select_and_execute(button, key_scheme_current); /* switch (button) { case BUTTON_F2: set_loop_mode(loop_mode + 1); break; case BUTTON_OFF: quit_requested = true; break; case BUTTON_PLAY: if (paused) { mpeg_resume(); } else { mpeg_pause(); } paused = !paused; break; case BUTTON_ON | BUTTON_RIGHT: case BUTTON_ON | BUTTON_RIGHT | BUTTON_REPEAT: if (pitch < 200) { pitch++; #ifdef HAVE_MAS3587F mpeg_set_pitch(pitch); #endif } break; case BUTTON_ON | BUTTON_LEFT: case BUTTON_ON | BUTTON_LEFT | BUTTON_REPEAT: if (pitch > 50) { pitch--; #ifdef HAVE_MAS3587F mpeg_set_pitch(pitch); #endif } break; case BUTTON_ON | BUTTON_PLAY: if (pitch != 100) { pitch = 100; #ifdef HAVE_MAS3587F mpeg_set_pitch(pitch); #endif } break; } */ if (validation_start == ~(unsigned int)0) { if (elapsed < range_end && elapsed > range_start) { validation_start = elapsed; } else { int endx = time_to_xpos(range_end); validation_start = xpos_to_time(endx - 2); } last_elapsed = elapsed + 1; } else { if ((last_elapsed <= validation_start) && (elapsed > validation_start)) { osci_valid = true; } last_elapsed = elapsed; } update_data(); } } return xpos_to_time(split_x); } void split_editor_main(void) { /* dummy inits, belong in main */ load_scheme(NULL); lcd_clear_display(); lcd_update(); lcd_setmargins(0,0); id3 = mpeg_current_track(); if (id3 != NULL) { split_editor(id3, id3->elapsed, MIN_RANGE_SIZE * 8); } }