Use the AMS_LOWMEM define to indicate memory size as the .lds files do in config...
[kugel-rb.git] / apps / plugins / splitedit.c
blob81a8b2416a42a7fe656ceda4c5b2b1fd79af9a6b
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Philipp Pertermann
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "plugin.h"
24 PLUGIN_HEADER
26 /* variable button definitions */
27 #if CONFIG_KEYPAD == RECORDER_PAD
28 #define SPLITEDIT_QUIT BUTTON_OFF
29 #define SPLITEDIT_PLAY BUTTON_PLAY
30 #define SPLITEDIT_SAVE BUTTON_F1
31 #define SPLITEDIT_LOOP_MODE BUTTON_F2
32 #define SPLITEDIT_SCALE BUTTON_F3
33 #define SPLITEDIT_SPEED50 (BUTTON_ON | BUTTON_LEFT)
34 #define SPLITEDIT_SPEED100 (BUTTON_ON | BUTTON_PLAY)
35 #define SPLITEDIT_SPEED150 (BUTTON_ON | BUTTON_RIGHT)
36 #define SPLITEDIT_MENU_RUN BUTTON_PLAY
38 #elif CONFIG_KEYPAD == ONDIO_PAD
39 #define SPLITEDIT_QUIT BUTTON_OFF
40 #define SPLITEDIT_PLAY_PRE BUTTON_MENU
41 #define SPLITEDIT_PLAY (BUTTON_MENU | BUTTON_REL)
42 #define SPLITEDIT_SAVE (BUTTON_MENU | BUTTON_LEFT)
43 #define SPLITEDIT_LOOP_MODE (BUTTON_MENU | BUTTON_UP)
44 #define SPLITEDIT_SCALE (BUTTON_MENU | BUTTON_RIGHT)
45 #define SPLITEDIT_MENU_RUN BUTTON_RIGHT
47 #elif CONFIG_KEYPAD == IRIVER_H100_PAD
48 #define SPLITEDIT_QUIT BUTTON_OFF
49 #define SPLITEDIT_PLAY BUTTON_ON
50 #define SPLITEDIT_SAVE BUTTON_SELECT
51 #define SPLITEDIT_LOOP_MODE BUTTON_MODE
52 #define SPLITEDIT_SCALE (BUTTON_REC | BUTTON_UP)
53 #define SPLITEDIT_SPEED50 (BUTTON_REC | BUTTON_LEFT)
54 #define SPLITEDIT_SPEED100 (BUTTON_REC | BUTTON_DOWN)
55 #define SPLITEDIT_SPEED150 (BUTTON_REC | BUTTON_RIGHT)
56 #define SPLITEDIT_MENU_RUN BUTTON_RIGHT
58 #define SPLITEDIT_RC_QUIT BUTTON_RC_STOP
59 #endif
61 #define BMPHEIGHT 7
62 #define BMPWIDTH 13
63 unsigned char LOOP_BMP[][13] =
65 {0xfc,0x00,0x10,0x11,0x93,0x7f,0x13,0x11,0x7c,0x38,0x10,0x00,0x7c}, /*ALL */
66 {0x81,0x03,0x7f,0x03,0x91,0x10,0x10,0x10,0x7c,0x38,0x10,0x00,0x7c}, /*FROM*/
67 {0xfc,0x00,0x10,0x10,0x90,0x10,0x7c,0x38,0x11,0x03,0x7f,0x03,0x01}, /*TO */
68 {0x80,0x10,0x10,0x11,0x93,0x7f,0x13,0x11,0x10,0x7c,0x38,0x10,0x00}, /*FREE*/
71 unsigned char CUT_BMP[] =
73 0xc1,0x63,0x63,0x36,0xb6,0x1c,0x1c,0x36,0x77,0x55,0x55,0x55,0x32,
76 unsigned char SCALE_BMP[][13] =
78 {0x80,0x06,0x49,0x66,0xb0,0x18,0x0c,0x06,0x33,0x49,0x30,0x00,0x00}, /*lin*/
79 {0x80,0x30,0x78,0x48,0xff,0x7f,0x00,0x7f,0x7f,0x48,0x78,0x30,0x00}, /*db*/
82 #define TIMEBAR_Y 9
83 #define TIMEBAR_HEIGHT 4
85 #define OSCI_X 0
86 #define OSCI_Y (TIMEBAR_Y + TIMEBAR_HEIGHT + 1)
87 #define OSCI_WIDTH LCD_WIDTH
88 #define OSCI_HEIGHT (LCD_HEIGHT - BMPHEIGHT - OSCI_Y - 1)
90 /* Indices of the menu items in the save editor, see save_editor */
91 #define SE_PART1_SAVE 0
92 #define SE_PART1_NAME 1
93 #define SE_PART2_SAVE 2
94 #define SE_PART2_NAME 3
95 #define SE_SAVE 4
96 #define SE_COUNT 5
98 /* contains the file name of the song that is to be split */
99 static char path_mp3[MAX_PATH];
101 /* Exit code of this plugin */
102 static enum plugin_status splitedit_exit_code = PLUGIN_OK;
104 /* The range in time that the displayed aerea comprises */
105 static unsigned int range_start = 0;
106 static unsigned int range_end = 0;
108 /* The range in time that is being looped */
109 static unsigned int play_start = 0;
110 static unsigned int play_end = 0;
112 /* Point in time (pixel) at which the split mark is set */
113 static int split_x = OSCI_X + (OSCI_WIDTH / 2);
115 /* Contains the peak values */
116 static unsigned char osci_buffer[OSCI_WIDTH];
118 /* if true peak values from a previous loop are only overwritten
119 if the new value is greater than the old value */
120 static bool osci_valid = false;
123 * point in time from which on the osci_buffer is invalid
124 * if set to ~(unsigned int)0 the entire osci_buffer is invalid
126 static unsigned int validation_start = ~(unsigned int)0;
128 /* all the visible aerea is looped */
129 #define LOOP_MODE_ALL 0
131 /* loop starts at split point, ends at right visible border */
132 #define LOOP_MODE_FROM 1
134 /* loop start at left visible border, ends at split point */
135 #define LOOP_MODE_TO 2
137 /* let the song play without looping */
138 #define LOOP_MODE_FREE 3
140 /* see LOOP_MODE_XXX constants vor valid values */
141 static int loop_mode = LOOP_MODE_FREE;
143 /* minimal allowed timespan (ms) of the visible (and looped) aerea*/
144 #define MIN_RANGE_SIZE 1000
146 /* Format time into buf.
148 * buf - buffer to format to.
149 * buf_size - size of buffer.
150 * time - time to format, in milliseconds.
152 static void format_time_ms(char* buf, int buf_size, int time)
154 rb->snprintf(buf, buf_size, "%d:%02d:%03d", time / 60000,
155 time % 60000 / 1000, (time % 60000) % 1000);
159 * converts screen coordinate (pixel) to time (ms)
161 static int xpos_to_time(int xpos)
163 int retval = 0;
164 int range = range_end - range_start;
165 retval = range_start + (((xpos - OSCI_X) * range) / OSCI_WIDTH);
166 return retval;
170 * Converts time (ms) to screen coordinates (pixel).
172 static int time_to_xpos(unsigned int time)
174 int retval = OSCI_X;
176 /* clip the range */
177 if (time < range_start)
179 retval = OSCI_X;
181 else
182 if (time >= range_end)
184 retval = OSCI_X + OSCI_WIDTH;
187 /* do the calculation */
188 else
190 int range = range_end - range_start;
191 retval = OSCI_X + ((time - range_start) * OSCI_WIDTH) / range ;
193 return retval;
197 * Updates the display of the textual data only.
199 static void update_data(void)
201 char buf[20];
202 char timebuf[10];
203 int w, h;
205 /* split point */
206 format_time_ms(timebuf, sizeof buf, xpos_to_time(split_x));
207 rb->snprintf(buf, sizeof buf, "Split at: %s", timebuf);
209 rb->lcd_getstringsize(buf, &w, &h);
211 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
212 rb->lcd_fillrect(0, 0, LCD_WIDTH, h);
213 rb->lcd_set_drawmode(DRMODE_SOLID);
214 rb->lcd_puts(0, 0, buf);
215 rb->lcd_update_rect(0, 0, LCD_WIDTH, h);
219 * Displays which part of the song is visible
220 * in the osci.
222 static void update_timebar(struct mp3entry *mp3)
224 rb->gui_scrollbar_draw
226 rb->screens[SCREEN_MAIN],0, TIMEBAR_Y, LCD_WIDTH, TIMEBAR_HEIGHT,
227 mp3->length, range_start, range_end,
228 HORIZONTAL
230 rb->lcd_update_rect(0, TIMEBAR_Y, LCD_WIDTH, TIMEBAR_HEIGHT);
234 * Marks the entire area of the osci buffer invalid.
235 * It will be drawn with new values in the next loop.
237 void splitedit_invalidate_osci(void)
239 osci_valid = false;
240 validation_start = ~(unsigned int)0;
244 * Returns the loop mode. See the LOOP_MODE_XXX constants above.
246 int splitedit_get_loop_mode(void)
248 return loop_mode;
252 * Updates the icons that display the Fn key hints.
254 static void update_icons(void)
256 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
257 rb->lcd_fillrect(0, LCD_HEIGHT - BMPHEIGHT, LCD_WIDTH, BMPHEIGHT);
258 rb->lcd_set_drawmode(DRMODE_SOLID);
260 /* The CUT icon */
261 rb->lcd_mono_bitmap(CUT_BMP,
262 LCD_WIDTH / 3 / 2 - BMPWIDTH / 2, LCD_HEIGHT - BMPHEIGHT,
263 BMPWIDTH, BMPHEIGHT);
265 /* The loop mode icon */
266 rb->lcd_mono_bitmap(LOOP_BMP[splitedit_get_loop_mode()],
267 LCD_WIDTH/3 + LCD_WIDTH/3 / 2 - BMPWIDTH/2, LCD_HEIGHT - BMPHEIGHT,
268 BMPWIDTH, BMPHEIGHT);
270 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
271 /* The scale icon */
272 rb->lcd_mono_bitmap(SCALE_BMP[rb->peak_meter_get_use_dbfs() ? 1 : 0],
273 2 *LCD_WIDTH/3 + LCD_WIDTH/3 / 2 - BMPWIDTH/2, LCD_HEIGHT - BMPHEIGHT,
274 BMPWIDTH, BMPHEIGHT);
275 #else
277 static int idx;
278 if (idx < 0 || idx > 1) idx = 0;
279 idx = 1 - idx;
280 rb->lcd_mono_bitmap(SCALE_BMP[idx],
281 2 *LCD_WIDTH/3 + LCD_WIDTH/3 / 2 - BMPWIDTH/2, LCD_HEIGHT - BMPHEIGHT,
282 BMPWIDTH, BMPHEIGHT);
284 #endif
286 rb->lcd_update_rect(0, LCD_HEIGHT - BMPHEIGHT, LCD_WIDTH, BMPHEIGHT);
290 * Sets the loop mode. See the LOOP_MODE_XXX constants above.
292 void splitedit_set_loop_mode(int mode)
294 int old_loop_mode = loop_mode;
295 /* range restriction */
296 loop_mode = mode % (LOOP_MODE_FREE + 1);
297 switch (loop_mode)
299 case LOOP_MODE_ALL:
300 play_start = range_start;
301 play_end = range_end;
302 break;
304 case LOOP_MODE_FROM:
305 play_start = xpos_to_time(split_x);
306 play_end = range_end;
307 break;
309 case LOOP_MODE_TO:
310 play_start = range_start;
311 play_end = xpos_to_time(split_x);
312 break;
314 case LOOP_MODE_FREE:
315 /* play_start is used when the song plays beyond its end */
316 play_start = range_start;
317 play_end = range_end;
318 break;
321 if (loop_mode != old_loop_mode)
323 update_icons();
328 * Readraws the osci without clear.
330 static void redraw_osci(void)
332 int x;
333 for (x = 0; x < OSCI_WIDTH; x++)
335 if (osci_buffer[x] > 0)
337 rb->lcd_vline
339 OSCI_X + x, OSCI_Y + OSCI_HEIGHT - 1,
340 OSCI_Y + OSCI_HEIGHT - osci_buffer[x] - 1
347 * Sets the range of time in which the user can finetune the split
348 * point. The split point is the center of the time range.
350 static void set_range_by_time(
351 struct mp3entry *mp3,
352 unsigned int split_time,
353 unsigned int range)
355 if (mp3 != NULL)
357 if (range < MIN_RANGE_SIZE)
359 range = MIN_RANGE_SIZE;
361 range_start = (split_time > range / 2) ? (split_time - range / 2) : 0;
362 range_end = MIN(range_start + range, mp3->length);
363 split_x = time_to_xpos(split_time);
365 splitedit_invalidate_osci();
367 /* this sets the play_start / play_end */
368 splitedit_set_loop_mode(splitedit_get_loop_mode());
370 update_data();
371 update_timebar(mp3);
376 * Set the split point in screen coordinates
378 void splitedit_set_split_x(int newx)
380 int minx = split_x - 2 > 0 ? split_x - 2: 0;
382 /* remove old split point from screen, only if moved */
383 if (split_x != newx)
385 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
386 rb->lcd_fillrect(minx, OSCI_Y, 5, 1);
387 rb->lcd_fillrect(split_x-1 > 0 ? split_x - 1: 0, OSCI_Y + 1, 3, 1);
388 rb->lcd_fillrect(split_x, OSCI_Y + 2, 1, OSCI_HEIGHT - 2);
389 rb->lcd_set_drawmode(DRMODE_SOLID);
390 rb->lcd_update_rect(minx, OSCI_Y, 5, OSCI_HEIGHT);
393 if (newx >= OSCI_X && newx < OSCI_X + OSCI_WIDTH)
395 split_x = newx;
396 /* in LOOP_FROM / LOOP_TO modes play_start /play_end must be updated */
397 splitedit_set_loop_mode(splitedit_get_loop_mode());
399 /* display new split time */
400 update_data();
403 /* display new split point */
404 minx = split_x - 2 > 0 ? split_x - 2: 0;
405 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
406 rb->lcd_fillrect(minx, OSCI_Y, 5, 1);
407 rb->lcd_fillrect(split_x - 1 > 0 ? split_x - 1: 0, OSCI_Y + 1, 3, 1);
408 rb->lcd_fillrect(split_x, OSCI_Y + 2, 1, OSCI_HEIGHT - 2);
409 rb->lcd_set_drawmode(DRMODE_SOLID);
410 rb->lcd_update_rect(minx, OSCI_Y, 5, OSCI_HEIGHT);
414 * returns the split point in screen coordinates
416 int splitedit_get_split_x(void)
418 return split_x;
422 * Clears the osci area and redraws it
424 static void update_osci(void)
426 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
427 rb->lcd_fillrect(OSCI_X, OSCI_Y, OSCI_WIDTH, OSCI_HEIGHT);
428 rb->lcd_set_drawmode(DRMODE_SOLID);
429 redraw_osci();
430 splitedit_set_split_x(splitedit_get_split_x());
431 rb->lcd_update_rect(OSCI_X, OSCI_Y, OSCI_WIDTH, OSCI_HEIGHT);
435 * Zooms the visable and loopable range by the factor
436 * (counter / denominator). The split point is used as
437 * center point of the new selected range.
439 static void zoom(struct mp3entry *mp3, int counter, int denominator)
441 unsigned char oldbuf[OSCI_WIDTH];
442 int oldrange = range_end - range_start;
443 int range = oldrange * counter / denominator;
444 int i;
445 int oldindex;
446 int oldsplitx;
447 int splitx;
448 int split;
450 /* for stretching / shrinking a second buffer is needed */
451 rb->memcpy(&oldbuf, &osci_buffer, sizeof osci_buffer);
453 /* recalculate the new range and split point */
454 oldsplitx = split_x;
455 split = xpos_to_time(split_x);
457 set_range_by_time(mp3, split, range);
458 range = range_end - range_start;
460 splitx = time_to_xpos(split);
462 /* strech / shrink the existing osci buffer */
463 for (i = 0; i < OSCI_WIDTH; i++)
465 /* oldindex = (i + OSCI_X - splitx) * range / oldrange + oldsplitx ;*/
466 oldindex = (i*range / oldrange) + oldsplitx - (splitx*range /oldrange);
467 if (oldindex >= 0 && oldindex < OSCI_WIDTH)
469 osci_buffer[i] = oldbuf[oldindex];
471 else
473 osci_buffer[i] = 0;
477 splitx = time_to_xpos(split);
478 splitedit_set_split_x(splitx);
479 splitedit_invalidate_osci();
483 static void scroll(struct mp3entry *mp3)
485 zoom(mp3, 1, 1);
486 rb->lcd_update_rect(OSCI_X, OSCI_Y, LCD_WIDTH, OSCI_HEIGHT);
487 update_osci();
488 update_data();
492 * Zooms in by 3/4
494 void splitedit_zoom_in(struct mp3entry *mp3)
496 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
497 rb->lcd_fillrect(OSCI_X, OSCI_Y, OSCI_WIDTH, OSCI_HEIGHT);
498 rb->lcd_set_drawmode(DRMODE_SOLID);
499 zoom(mp3, 3, 4);
500 rb->lcd_update_rect(OSCI_X, OSCI_Y, LCD_WIDTH, OSCI_HEIGHT);
501 update_osci();
502 update_data();
506 * Zooms out by 4/3
508 void splitedit_zoom_out(struct mp3entry *mp3)
510 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
511 rb->lcd_fillrect(OSCI_X, OSCI_Y, LCD_WIDTH, OSCI_HEIGHT);
512 rb->lcd_set_drawmode(DRMODE_SOLID);
513 zoom(mp3, 4, 3);
514 rb->lcd_update_rect(OSCI_X, OSCI_Y, LCD_WIDTH, OSCI_HEIGHT);
515 update_osci();
516 update_data();
520 * Append part_no to the file name.
522 static void generateFileName(char* file_name, int part_no)
524 if (rb->strlen(file_name) <MAX_PATH)
526 int len = rb->strlen(file_name);
527 int ext_len = rb->strlen(".mp3");
528 if (rb->strcasecmp(
529 &file_name[len - ext_len],
530 ".mp3") == 0)
532 int i = 0;
533 /* shift the extension one position to the right*/
534 for (i = len; i > len - ext_len; i--)
536 file_name[i] = file_name[i - 1];
538 file_name[len - ext_len] = '0' + part_no;
540 else
542 rb->splash(0, "wrong extension");
543 rb->button_get(true);
544 rb->button_get(true);
547 else
549 rb->splash(0, "name too long");
550 rb->button_get(true);
551 rb->button_get(true);
558 * Copy bytes from src to dest while displaying a progressbar.
559 * The files must be already open.
561 static int copy_file(
562 int dest,
563 int src,
564 unsigned int bytes,
565 int prg_y,
566 int prg_h)
568 long button;
569 unsigned char *buffer;
570 unsigned int i = 0;
571 ssize_t bytes_read = 1; /* ensure the for loop is executed */
572 size_t buffer_size;
573 buffer = rb->plugin_get_buffer(&buffer_size);
575 for (i = 0; i < bytes && bytes_read > 0; i += bytes_read)
577 ssize_t bytes_written;
578 unsigned int bytes_to_read =
579 bytes - i > buffer_size ? buffer_size : bytes - i;
580 bytes_read = rb->read(src, buffer, bytes_to_read);
581 bytes_written = rb->write(dest, buffer, bytes_read);
583 if (bytes_written < 0) {
584 rb->splash(0, "Write failed in copy.");
585 rb->button_get(true);
586 rb->button_get(true);
587 return -1;
590 button = rb->button_get(false);
592 if (button == SPLITEDIT_QUIT
593 #ifdef SPLITEDIT_RC_QUIT
594 || button == SPLITEDIT_RC_QUIT:
595 #endif
597 rb->splash(0, "Aborting copy.");
598 rb->button_get(true);
599 rb->button_get(true);
600 return -1;
603 rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN],0, prg_y, LCD_WIDTH,
604 prg_h, bytes, 0, i, HORIZONTAL);
605 rb->lcd_update_rect(0, prg_y, LCD_WIDTH, prg_h);
608 return 0;
612 * Save the files, if the file_name is not NULL
614 static int save(
615 struct mp3entry *mp3,
616 char *file_name1,
617 char *file_name2,
618 int splittime)
620 int file1, file2, src_file;
621 unsigned int end = 0;
622 int retval = 0;
624 /* Verify that file 1 doesn't exit yet */
625 if (file_name1 != NULL)
627 file1 = rb->open(file_name1, O_RDONLY);
628 if (file1 >= 0)
630 rb->close(file1);
631 rb->splash(0, "File 1 exists. Please rename.");
632 rb->button_get(true);
633 rb->button_get(true);
634 return -1;
638 /* Verify that file 2 doesn't exit yet */
639 if (file_name2 != NULL)
641 file2 = rb->open(file_name2, O_RDONLY);
642 if (file2 >= 0)
644 rb->close(file2);
645 rb->splash(0, "File 2 exists. Please rename.");
646 rb->button_get(true);
647 rb->button_get(true);
648 return -2;
652 /* find the file position of the split point */
653 rb->audio_pause();
654 rb->audio_ff_rewind(splittime);
655 rb->yield();
656 rb->yield();
657 end = rb->audio_get_file_pos();
659 /* open the source file */
660 src_file = rb->open(mp3->path, O_RDONLY);
661 if (src_file >= 0)
663 int close_stat = 0;
664 int x, y;
665 long offset;
666 unsigned long last_header = rb->mpeg_get_last_header();
668 rb->lcd_getstringsize("M", &x, &y);
670 /* Find the next frame boundary */
671 rb->lseek(src_file, end, SEEK_SET);
672 rb->find_next_frame(src_file, &offset, 8000, last_header);
673 rb->lseek(src_file, 0, SEEK_SET);
674 end += offset;
676 /* write the file 1 */
677 if (file_name1 != NULL)
679 file1 = rb->open (file_name1, O_WRONLY | O_CREAT);
680 if (file1 >= 0)
682 int rc = copy_file(file1, src_file, end, y*2 + 1, y -1);
683 close_stat = rb->close(file1);
685 if (close_stat != 0)
687 rb->splashf(0, "failed closing file1: error %d", close_stat);
688 rb->button_get(true);
689 rb->button_get(true);
690 } else {
691 /* If there was an error, cleanup */
692 if (rc) {
693 rb->remove(file_name1);
697 else
699 rb->splashf(0, "Can't write File1: error %d", file1);
700 rb->button_get(true);
701 rb->button_get(true);
702 retval = -1;
705 /* if file1 hasn't been written we're not at the split point yet */
706 else
708 if (rb->lseek(src_file, end, SEEK_SET) < (off_t)end)
710 rb->splashf(0, "Src file to short: error %d", src_file);
711 rb->button_get(true);
712 rb->button_get(true);
716 if (file_name2 != NULL)
718 /* write file 2 */
719 file2 = rb->open (file_name2, O_WRONLY | O_CREAT);
720 if (file2 >= 0)
722 end = mp3->filesize - end;
723 int rc = copy_file(file2, src_file, end, y * 5 + 1, y -1);
724 close_stat = rb->close(file2);
726 if (close_stat != 0)
728 rb->splashf(0, "failed: closing file2: error %d",
729 close_stat);
730 rb->button_get(true);
731 rb->button_get(true);
732 } else {
733 /* If there was an error, cleanup */
734 if (rc) {
735 rb->remove(file_name2);
739 else
741 rb->splashf(0, "Can't write File2: error %d", file2);
742 rb->button_get(true);
743 rb->button_get(true);
744 retval = -2;
748 close_stat = rb->close(src_file);
749 if (close_stat != 0)
751 rb->splashf(0, "failed: closing src: error %d", close_stat);
752 rb->button_get(true);
753 rb->button_get(true);
756 else
758 rb->splash(0, "Source file not found");
759 rb->button_get(true);
760 rb->button_get(true);
761 retval = -3;
764 rb->audio_resume();
766 return retval;
770 * Let the user choose which file to save with which name
772 static void save_editor(struct mp3entry *mp3, int splittime)
774 bool exit_request = false;
775 int choice = 0;
776 int button = BUTTON_NONE;
777 char part1_name [MAX_PATH];
778 char part2_name [MAX_PATH];
779 bool part1_save = true;
780 bool part2_save = true;
782 /* file name for left part */
783 rb->strncpy(part1_name, mp3->path, MAX_PATH);
784 generateFileName(part1_name, 1);
786 /* file name for right part */
787 rb->strncpy(part2_name, mp3->path, MAX_PATH);
788 generateFileName(part2_name, 2);
790 while (!exit_request)
792 int pos;
793 rb->lcd_clear_display();
795 /* Save file1? */
796 rb->lcd_puts_style(0, 0, "Save part 1?", choice == SE_PART1_SAVE);
797 rb->lcd_puts(13, 0, part1_save?"yes":"no");
799 /* trim to display the filename without path */
800 for (pos = rb->strlen(part1_name); pos > 0; pos--)
802 if (part1_name[pos] == '/')
803 break;
805 pos++;
807 /* File name 1 */
808 rb->lcd_puts_scroll_style(0, 1,
809 &part1_name[pos], choice == SE_PART1_NAME);
811 /* Save file2? */
812 rb->lcd_puts_style(0, 3, "Save part 2?", choice == SE_PART2_SAVE);
813 rb->lcd_puts(13, 3, part2_save?"yes":"no");
815 /* trim to display the filename without path */
816 for (pos = rb->strlen(part2_name); pos > 0; pos --)
818 if (part2_name[pos] == '/')
819 break;
821 pos++;
823 /* File name 2 */
824 rb->lcd_puts_scroll_style(0, 4,
825 &part2_name[pos], choice == SE_PART2_NAME);
827 /* Save */
828 rb->lcd_puts_style(0, 6, "Save", choice == SE_SAVE);
830 rb->lcd_update();
833 button = rb->button_get(true);
834 switch (button)
836 case BUTTON_UP:
837 choice = (choice + SE_COUNT - 1) % SE_COUNT;
838 break;
840 case BUTTON_DOWN:
841 choice = (choice + 1) % SE_COUNT;
842 break;
844 case SPLITEDIT_MENU_RUN:
845 switch (choice)
847 int saved;
849 case SE_PART1_SAVE:
850 part1_save = !part1_save;
851 break;
853 case SE_PART1_NAME:
854 rb->kbd_input(part1_name, MAX_PATH);
855 break;
857 case SE_PART2_SAVE:
858 part2_save = !part2_save;
859 break;
861 case SE_PART2_NAME:
862 rb->kbd_input(part2_name, MAX_PATH);
863 break;
865 case SE_SAVE:
866 rb->lcd_stop_scroll();
867 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
868 rb->lcd_fillrect(0, 6*8, LCD_WIDTH, LCD_HEIGHT);
869 rb->lcd_set_drawmode(DRMODE_SOLID);
870 saved = save
872 mp3,
873 part1_save?part1_name:NULL,
874 part2_save?part2_name:NULL,
875 splittime
878 /* if something failed the user may go on choosing */
879 if (saved >= 0)
881 exit_request = true;
883 break;
885 break;
886 #ifdef SPLITEDIT_RC_QUIT
887 case SPLITEDIT_RC_QUIT:
888 #endif
889 case SPLITEDIT_QUIT:
890 exit_request = true;
891 break;
893 default:
894 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
896 splitedit_exit_code = PLUGIN_USB_CONNECTED;
897 exit_request = true;
899 break;
905 * The main loop of the editor
907 unsigned long splitedit_editor(struct mp3entry * mp3_to_split,
908 unsigned int split_time,
909 unsigned int range)
911 int button = BUTTON_NONE;
912 int lastbutton = BUTTON_NONE;
913 struct mp3entry *mp3 = mp3_to_split;
914 unsigned int last_elapsed = 0;
915 int lastx = OSCI_X + (OSCI_WIDTH / 2);
916 int retval = -1;
918 if (mp3 != NULL)
920 /*unsigned short scheme = SCHEME_SPLIT_EDITOR;*/
921 bool exit_request = false;
922 set_range_by_time(mp3, split_time, range);
923 splitedit_set_loop_mode(LOOP_MODE_ALL);
924 update_icons();
926 /*while (scheme != SCHEME_RETURN) {*/
927 while (!exit_request)
929 unsigned int elapsed ;
930 int x ;
932 /* get position */
933 elapsed = mp3->elapsed;
934 x = time_to_xpos(elapsed);
936 /* are we still in the zoomed range? */
937 if (elapsed > play_start && elapsed < play_end)
939 /* read volume info */
940 unsigned short volume;
941 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
942 volume = rb->mas_codec_readreg(0x0c);
943 volume += rb->mas_codec_readreg(0x0d);
944 volume = volume / 2;
945 volume = rb->peak_meter_scale_value(volume, OSCI_HEIGHT);
946 #else
947 volume = OSCI_HEIGHT / 2;
948 #endif
950 /* update osci_buffer */
951 if (osci_valid || lastx == x)
953 int index = x - OSCI_X;
954 osci_buffer[index] = MAX(osci_buffer[index], volume);
956 else
958 int i;
959 osci_buffer[x - OSCI_X] = volume;
960 for (i = lastx + 1; i < x; i++)
962 osci_buffer[i - OSCI_X] = 0;
966 /* make room */
967 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
968 rb->lcd_fillrect(lastx + 1, OSCI_Y, x - lastx, OSCI_HEIGHT);
969 rb->lcd_set_drawmode(DRMODE_SOLID);
970 /* draw a value */
971 if (osci_buffer[x - OSCI_X] > 0)
973 int i;
974 for (i = lastx +1; i <= x; i++)
976 rb->lcd_vline
978 i, OSCI_Y + OSCI_HEIGHT - 1,
979 OSCI_Y + OSCI_HEIGHT - osci_buffer[i - OSCI_X]-1
984 /* mark the current position */
985 if (lastx != x)
987 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
988 rb->lcd_fillrect(lastx, OSCI_Y, 1, OSCI_HEIGHT);
989 rb->lcd_fillrect(x, OSCI_Y, 1, OSCI_HEIGHT);
990 rb->lcd_set_drawmode(DRMODE_SOLID);
993 /* mark the split point */
994 if ((x > split_x - 2) && (lastx < split_x + 3))
996 if ((lastx < split_x) && (x >= split_x))
998 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
999 rb->lcd_fillrect
1001 split_x, OSCI_Y + 2,
1002 1, OSCI_HEIGHT - 2
1004 rb->lcd_set_drawmode(DRMODE_SOLID);
1006 rb->lcd_hline(split_x -2, split_x + 2, OSCI_Y);
1007 rb->lcd_hline(split_x-1, split_x +1,OSCI_Y+1);
1010 /* make visible */
1011 if (lastx <= x)
1013 rb->lcd_update_rect(lastx, OSCI_Y, x-lastx+1, OSCI_HEIGHT);
1015 else
1017 rb->lcd_update_rect
1019 lastx, OSCI_Y,
1020 OSCI_X + OSCI_WIDTH - lastx, OSCI_HEIGHT
1022 rb->lcd_update_rect(0, OSCI_Y, x + 1, OSCI_HEIGHT);
1025 lastx = x;
1028 /* we're not in the zoom range -> rewind */
1029 else
1031 if (elapsed >= play_end)
1033 switch (splitedit_get_loop_mode())
1035 unsigned int range_width;
1037 case LOOP_MODE_ALL:
1038 case LOOP_MODE_TO:
1039 rb->audio_pause();
1040 rb->audio_ff_rewind(range_start);
1041 #if (CONFIG_STORAGE & STORAGE_MMC)
1042 /* MMC is slow - wait some time to allow track reload to finish */
1043 rb->sleep(HZ/20);
1044 if (mp3->elapsed > play_end) /* reload in progress */
1045 rb->splash(10*HZ, "Wait - reloading");
1046 #endif
1047 rb->audio_resume();
1048 break;
1050 case LOOP_MODE_FROM:
1051 rb->audio_pause();
1052 rb->audio_ff_rewind(xpos_to_time(split_x));
1053 #if (CONFIG_STORAGE & STORAGE_MMC)
1054 /* MMC is slow - wait some time to allow track reload to finish */
1055 rb->sleep(HZ/20);
1056 if (mp3->elapsed > play_end) /* reload in progress */
1057 rb->splash(10*HZ, "Wait - reloading");
1058 #endif
1059 rb->audio_resume();
1060 break;
1062 case LOOP_MODE_FREE:
1063 range_width = range_end - range_start;
1064 set_range_by_time(mp3,
1065 range_end + range_width / 2, range_width);
1067 /* play_end und play_start anpassen */
1068 splitedit_set_loop_mode(LOOP_MODE_FREE);
1069 rb->memset(osci_buffer, 0, sizeof osci_buffer);
1070 update_osci();
1071 rb->lcd_update();
1072 break;
1077 button = rb->button_get(false);
1078 rb->yield();
1080 /* here the evaluation of the key scheme starts.
1081 All functions the user triggers are called from
1082 within execute_scheme */
1083 /* key_scheme_execute(button, &scheme); */
1084 switch (button)
1086 case SPLITEDIT_PLAY:
1087 #ifdef SPLITEDIT_PLAY_PRE
1088 if (lastbutton != SPLITEDIT_PLAY_PRE)
1089 break;
1090 #endif
1091 rb->audio_pause();
1092 rb->audio_ff_rewind(xpos_to_time(split_x));
1093 rb->audio_resume();
1094 break;
1096 case BUTTON_UP:
1097 splitedit_zoom_in(mp3);
1098 lastx = time_to_xpos(mp3->elapsed);
1099 break;
1101 case BUTTON_DOWN:
1102 splitedit_zoom_out(mp3);
1103 lastx = time_to_xpos(mp3->elapsed);
1104 break;
1106 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
1107 #ifdef SPLITEDIT_SPEED100
1108 case SPLITEDIT_SPEED150:
1109 rb->sound_set_pitch(1500);
1110 splitedit_invalidate_osci();
1111 break;
1113 case SPLITEDIT_SPEED100:
1114 rb->sound_set_pitch(1000);
1115 splitedit_invalidate_osci();
1116 break;
1118 case SPLITEDIT_SPEED50:
1119 rb->sound_set_pitch(500);
1120 splitedit_invalidate_osci();
1121 break;
1122 #endif
1123 #endif
1125 case BUTTON_LEFT:
1126 case BUTTON_LEFT | BUTTON_REPEAT:
1127 if (splitedit_get_split_x() > OSCI_X + 2)
1129 splitedit_set_split_x(splitedit_get_split_x() - 1);
1131 else
1133 scroll(mp3);
1134 lastx = time_to_xpos(mp3->elapsed);
1136 break;
1138 case BUTTON_RIGHT:
1139 case BUTTON_RIGHT | BUTTON_REPEAT:
1140 if (splitedit_get_split_x() < OSCI_X + OSCI_WIDTH-3)
1142 splitedit_set_split_x(splitedit_get_split_x() + 1);
1144 else
1146 scroll(mp3);
1147 lastx = time_to_xpos(mp3->elapsed);
1149 break;
1151 case SPLITEDIT_SAVE:
1152 save_editor(mp3, xpos_to_time(split_x));
1153 rb->lcd_clear_display();
1154 update_osci();
1155 update_timebar(mp3);
1156 update_icons();
1157 break;
1159 case SPLITEDIT_LOOP_MODE:
1160 splitedit_set_loop_mode(splitedit_get_loop_mode() + 1);
1161 update_icons();
1162 break;
1164 case SPLITEDIT_SCALE:
1165 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
1166 rb->peak_meter_set_use_dbfs(!rb->peak_meter_get_use_dbfs());
1167 #endif
1168 splitedit_invalidate_osci();
1169 update_icons();
1170 break;
1172 #ifdef SPLITEDIT_RC_QUIT
1173 case SPLITEDIT_RC_QUIT:
1174 #endif
1175 case SPLITEDIT_QUIT:
1176 exit_request = true;
1177 break;
1179 default:
1180 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
1182 splitedit_exit_code = PLUGIN_USB_CONNECTED;
1183 exit_request = true;
1185 break;
1188 if (button != BUTTON_NONE)
1189 lastbutton = button;
1191 if (validation_start == ~(unsigned int)0)
1193 if (elapsed < range_end && elapsed > range_start)
1195 validation_start = elapsed;
1197 else
1199 int endx = time_to_xpos(range_end);
1200 validation_start = xpos_to_time(endx - 2);
1202 last_elapsed = elapsed + 1;
1204 else
1206 if ((last_elapsed <= validation_start) &&
1207 (elapsed > validation_start))
1209 osci_valid = true;
1212 last_elapsed = elapsed;
1214 update_data();
1216 if (mp3 != rb->audio_current_track())
1218 struct mp3entry *new_mp3 = rb->audio_current_track();
1219 if (rb->strncasecmp(path_mp3, new_mp3->path,
1220 sizeof (path_mp3)))
1222 rb->splash(0, "Abort due to file change");
1223 rb->button_get(true);
1224 rb->button_get(true);
1225 exit_request = true;
1227 else
1229 mp3 = new_mp3;
1230 rb->audio_pause();
1231 rb->audio_flush_and_reload_tracks();
1232 rb->audio_ff_rewind(range_start);
1233 rb->audio_resume();
1237 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
1238 #ifdef SPLITEDIT_SPEED100
1239 rb->sound_set_pitch(1000); /* make sure to reset pitch */
1240 #endif
1241 #endif
1244 return retval;
1247 enum plugin_status plugin_start(const void* parameter)
1249 struct mp3entry* mp3;
1251 (void)parameter;
1252 rb->lcd_clear_display();
1253 rb->lcd_update();
1254 mp3 = rb->audio_current_track();
1255 if (mp3 != NULL)
1257 if (rb->audio_status() & AUDIO_STATUS_PAUSE)
1259 rb->audio_resume();
1261 splitedit_editor(mp3, mp3->elapsed, MIN_RANGE_SIZE * 8);
1263 else
1265 rb->splash(0, "Play or pause a mp3 file first.");
1266 rb->button_get(true);
1267 rb->button_get(true);
1269 return splitedit_exit_code;