1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
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 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
59 #define SPLITEDIT_QUIT (BUTTON_REC | BUTTON_REW)
60 #define SPLITEDIT_PLAY (BUTTON_REC | BUTTON_FFWD)
61 #define SPLITEDIT_SAVE BUTTON_FFWD
62 #define SPLITEDIT_LOOP_MODE BUTTON_REW
63 #define SPLITEDIT_SCALE BUTTON_UP
64 #define SPLITEDIT_SPEED50 BUTTON_LEFT
65 #define SPLITEDIT_SPEED100 BUTTON_DOWN
66 #define SPLITEDIT_SPEED150 BUTTON_RIGHT
67 #define SPLITEDIT_MENU_RUN BUTTON_PLAY
69 #define SPLITEDIT_RC_QUIT BUTTON_RC_STOP
74 unsigned char LOOP_BMP
[][13] =
76 {0xfc,0x00,0x10,0x11,0x93,0x7f,0x13,0x11,0x7c,0x38,0x10,0x00,0x7c}, /*ALL */
77 {0x81,0x03,0x7f,0x03,0x91,0x10,0x10,0x10,0x7c,0x38,0x10,0x00,0x7c}, /*FROM*/
78 {0xfc,0x00,0x10,0x10,0x90,0x10,0x7c,0x38,0x11,0x03,0x7f,0x03,0x01}, /*TO */
79 {0x80,0x10,0x10,0x11,0x93,0x7f,0x13,0x11,0x10,0x7c,0x38,0x10,0x00}, /*FREE*/
82 unsigned char CUT_BMP
[] =
84 0xc1,0x63,0x63,0x36,0xb6,0x1c,0x1c,0x36,0x77,0x55,0x55,0x55,0x32,
87 unsigned char SCALE_BMP
[][13] =
89 {0x80,0x06,0x49,0x66,0xb0,0x18,0x0c,0x06,0x33,0x49,0x30,0x00,0x00}, /*lin*/
90 {0x80,0x30,0x78,0x48,0xff,0x7f,0x00,0x7f,0x7f,0x48,0x78,0x30,0x00}, /*db*/
94 #define TIMEBAR_HEIGHT 4
97 #define OSCI_Y (TIMEBAR_Y + TIMEBAR_HEIGHT + 1)
98 #define OSCI_WIDTH LCD_WIDTH
99 #define OSCI_HEIGHT (LCD_HEIGHT - BMPHEIGHT - OSCI_Y - 1)
101 /* Indices of the menu items in the save editor, see save_editor */
102 #define SE_PART1_SAVE 0
103 #define SE_PART1_NAME 1
104 #define SE_PART2_SAVE 2
105 #define SE_PART2_NAME 3
109 /* contains the file name of the song that is to be split */
110 static char path_mp3
[MAX_PATH
];
112 /* Exit code of this plugin */
113 static enum plugin_status splitedit_exit_code
= PLUGIN_OK
;
115 /* The range in time that the displayed aerea comprises */
116 static unsigned int range_start
= 0;
117 static unsigned int range_end
= 0;
119 /* The range in time that is being looped */
120 static unsigned int play_start
= 0;
121 static unsigned int play_end
= 0;
123 /* Point in time (pixel) at which the split mark is set */
124 static int split_x
= OSCI_X
+ (OSCI_WIDTH
/ 2);
126 /* Contains the peak values */
127 static unsigned char osci_buffer
[OSCI_WIDTH
];
129 /* if true peak values from a previous loop are only overwritten
130 if the new value is greater than the old value */
131 static bool osci_valid
= false;
134 * point in time from which on the osci_buffer is invalid
135 * if set to ~(unsigned int)0 the entire osci_buffer is invalid
137 static unsigned int validation_start
= ~(unsigned int)0;
139 /* all the visible aerea is looped */
140 #define LOOP_MODE_ALL 0
142 /* loop starts at split point, ends at right visible border */
143 #define LOOP_MODE_FROM 1
145 /* loop start at left visible border, ends at split point */
146 #define LOOP_MODE_TO 2
148 /* let the song play without looping */
149 #define LOOP_MODE_FREE 3
151 /* see LOOP_MODE_XXX constants vor valid values */
152 static int loop_mode
= LOOP_MODE_FREE
;
154 /* minimal allowed timespan (ms) of the visible (and looped) aerea*/
155 #define MIN_RANGE_SIZE 1000
157 /* Format time into buf.
159 * buf - buffer to format to.
160 * buf_size - size of buffer.
161 * time - time to format, in milliseconds.
163 static void format_time_ms(char* buf
, int buf_size
, int time
)
165 rb
->snprintf(buf
, buf_size
, "%d:%02d:%03d", time
/ 60000,
166 time
% 60000 / 1000, (time
% 60000) % 1000);
170 * converts screen coordinate (pixel) to time (ms)
172 static int xpos_to_time(int xpos
)
175 int range
= range_end
- range_start
;
176 retval
= range_start
+ (((xpos
- OSCI_X
) * range
) / OSCI_WIDTH
);
181 * Converts time (ms) to screen coordinates (pixel).
183 static int time_to_xpos(unsigned int time
)
188 if (time
< range_start
)
193 if (time
>= range_end
)
195 retval
= OSCI_X
+ OSCI_WIDTH
;
198 /* do the calculation */
201 int range
= range_end
- range_start
;
202 retval
= OSCI_X
+ ((time
- range_start
) * OSCI_WIDTH
) / range
;
208 * Updates the display of the textual data only.
210 static void update_data(void)
217 format_time_ms(timebuf
, sizeof timebuf
, xpos_to_time(split_x
));
218 rb
->snprintf(buf
, sizeof buf
, "Split at: %s", timebuf
);
220 rb
->lcd_getstringsize(buf
, &w
, &h
);
222 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
223 rb
->lcd_fillrect(0, 0, LCD_WIDTH
, h
);
224 rb
->lcd_set_drawmode(DRMODE_SOLID
);
225 rb
->lcd_puts(0, 0, buf
);
226 rb
->lcd_update_rect(0, 0, LCD_WIDTH
, h
);
230 * Displays which part of the song is visible
233 static void update_timebar(struct mp3entry
*mp3
)
235 rb
->gui_scrollbar_draw
237 rb
->screens
[SCREEN_MAIN
],0, TIMEBAR_Y
, LCD_WIDTH
, TIMEBAR_HEIGHT
,
238 mp3
->length
, range_start
, range_end
,
241 rb
->lcd_update_rect(0, TIMEBAR_Y
, LCD_WIDTH
, TIMEBAR_HEIGHT
);
245 * Marks the entire area of the osci buffer invalid.
246 * It will be drawn with new values in the next loop.
248 void splitedit_invalidate_osci(void)
251 validation_start
= ~(unsigned int)0;
255 * Returns the loop mode. See the LOOP_MODE_XXX constants above.
257 int splitedit_get_loop_mode(void)
263 * Updates the icons that display the Fn key hints.
265 static void update_icons(void)
267 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
268 rb
->lcd_fillrect(0, LCD_HEIGHT
- BMPHEIGHT
, LCD_WIDTH
, BMPHEIGHT
);
269 rb
->lcd_set_drawmode(DRMODE_SOLID
);
272 rb
->lcd_mono_bitmap(CUT_BMP
,
273 LCD_WIDTH
/ 3 / 2 - BMPWIDTH
/ 2, LCD_HEIGHT
- BMPHEIGHT
,
274 BMPWIDTH
, BMPHEIGHT
);
276 /* The loop mode icon */
277 rb
->lcd_mono_bitmap(LOOP_BMP
[splitedit_get_loop_mode()],
278 LCD_WIDTH
/3 + LCD_WIDTH
/3 / 2 - BMPWIDTH
/2, LCD_HEIGHT
- BMPHEIGHT
,
279 BMPWIDTH
, BMPHEIGHT
);
281 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
283 rb
->lcd_mono_bitmap(SCALE_BMP
[rb
->peak_meter_get_use_dbfs() ? 1 : 0],
284 2 *LCD_WIDTH
/3 + LCD_WIDTH
/3 / 2 - BMPWIDTH
/2, LCD_HEIGHT
- BMPHEIGHT
,
285 BMPWIDTH
, BMPHEIGHT
);
289 if (idx
< 0 || idx
> 1) idx
= 0;
291 rb
->lcd_mono_bitmap(SCALE_BMP
[idx
],
292 2 *LCD_WIDTH
/3 + LCD_WIDTH
/3 / 2 - BMPWIDTH
/2, LCD_HEIGHT
- BMPHEIGHT
,
293 BMPWIDTH
, BMPHEIGHT
);
297 rb
->lcd_update_rect(0, LCD_HEIGHT
- BMPHEIGHT
, LCD_WIDTH
, BMPHEIGHT
);
301 * Sets the loop mode. See the LOOP_MODE_XXX constants above.
303 void splitedit_set_loop_mode(int mode
)
305 int old_loop_mode
= loop_mode
;
306 /* range restriction */
307 loop_mode
= mode
% (LOOP_MODE_FREE
+ 1);
311 play_start
= range_start
;
312 play_end
= range_end
;
316 play_start
= xpos_to_time(split_x
);
317 play_end
= range_end
;
321 play_start
= range_start
;
322 play_end
= xpos_to_time(split_x
);
326 /* play_start is used when the song plays beyond its end */
327 play_start
= range_start
;
328 play_end
= range_end
;
332 if (loop_mode
!= old_loop_mode
)
339 * Readraws the osci without clear.
341 static void redraw_osci(void)
344 for (x
= 0; x
< OSCI_WIDTH
; x
++)
346 if (osci_buffer
[x
] > 0)
350 OSCI_X
+ x
, OSCI_Y
+ OSCI_HEIGHT
- 1,
351 OSCI_Y
+ OSCI_HEIGHT
- osci_buffer
[x
] - 1
358 * Sets the range of time in which the user can finetune the split
359 * point. The split point is the center of the time range.
361 static void set_range_by_time(
362 struct mp3entry
*mp3
,
363 unsigned int split_time
,
368 if (range
< MIN_RANGE_SIZE
)
370 range
= MIN_RANGE_SIZE
;
372 range_start
= (split_time
> range
/ 2) ? (split_time
- range
/ 2) : 0;
373 range_end
= MIN(range_start
+ range
, mp3
->length
);
374 split_x
= time_to_xpos(split_time
);
376 splitedit_invalidate_osci();
378 /* this sets the play_start / play_end */
379 splitedit_set_loop_mode(splitedit_get_loop_mode());
387 * Set the split point in screen coordinates
389 void splitedit_set_split_x(int newx
)
391 int minx
= split_x
- 2 > 0 ? split_x
- 2: 0;
393 /* remove old split point from screen, only if moved */
396 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
397 rb
->lcd_fillrect(minx
, OSCI_Y
, 5, 1);
398 rb
->lcd_fillrect(split_x
-1 > 0 ? split_x
- 1: 0, OSCI_Y
+ 1, 3, 1);
399 rb
->lcd_fillrect(split_x
, OSCI_Y
+ 2, 1, OSCI_HEIGHT
- 2);
400 rb
->lcd_set_drawmode(DRMODE_SOLID
);
401 rb
->lcd_update_rect(minx
, OSCI_Y
, 5, OSCI_HEIGHT
);
404 if (newx
>= OSCI_X
&& newx
< OSCI_X
+ OSCI_WIDTH
)
407 /* in LOOP_FROM / LOOP_TO modes play_start /play_end must be updated */
408 splitedit_set_loop_mode(splitedit_get_loop_mode());
410 /* display new split time */
414 /* display new split point */
415 minx
= split_x
- 2 > 0 ? split_x
- 2: 0;
416 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
417 rb
->lcd_fillrect(minx
, OSCI_Y
, 5, 1);
418 rb
->lcd_fillrect(split_x
- 1 > 0 ? split_x
- 1: 0, OSCI_Y
+ 1, 3, 1);
419 rb
->lcd_fillrect(split_x
, OSCI_Y
+ 2, 1, OSCI_HEIGHT
- 2);
420 rb
->lcd_set_drawmode(DRMODE_SOLID
);
421 rb
->lcd_update_rect(minx
, OSCI_Y
, 5, OSCI_HEIGHT
);
425 * returns the split point in screen coordinates
427 int splitedit_get_split_x(void)
433 * Clears the osci area and redraws it
435 static void update_osci(void)
437 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
438 rb
->lcd_fillrect(OSCI_X
, OSCI_Y
, OSCI_WIDTH
, OSCI_HEIGHT
);
439 rb
->lcd_set_drawmode(DRMODE_SOLID
);
441 splitedit_set_split_x(splitedit_get_split_x());
442 rb
->lcd_update_rect(OSCI_X
, OSCI_Y
, OSCI_WIDTH
, OSCI_HEIGHT
);
446 * Zooms the visable and loopable range by the factor
447 * (counter / denominator). The split point is used as
448 * center point of the new selected range.
450 static void zoom(struct mp3entry
*mp3
, int counter
, int denominator
)
452 unsigned char oldbuf
[OSCI_WIDTH
];
453 int oldrange
= range_end
- range_start
;
454 int range
= oldrange
* counter
/ denominator
;
461 /* for stretching / shrinking a second buffer is needed */
462 rb
->memcpy(&oldbuf
, &osci_buffer
, sizeof osci_buffer
);
464 /* recalculate the new range and split point */
466 split
= xpos_to_time(split_x
);
468 set_range_by_time(mp3
, split
, range
);
469 range
= range_end
- range_start
;
471 splitx
= time_to_xpos(split
);
473 /* strech / shrink the existing osci buffer */
474 for (i
= 0; i
< OSCI_WIDTH
; i
++)
476 /* oldindex = (i + OSCI_X - splitx) * range / oldrange + oldsplitx ;*/
477 oldindex
= (i
*range
/ oldrange
) + oldsplitx
- (splitx
*range
/oldrange
);
478 if (oldindex
>= 0 && oldindex
< OSCI_WIDTH
)
480 osci_buffer
[i
] = oldbuf
[oldindex
];
488 splitx
= time_to_xpos(split
);
489 splitedit_set_split_x(splitx
);
490 splitedit_invalidate_osci();
494 static void scroll(struct mp3entry
*mp3
)
497 rb
->lcd_update_rect(OSCI_X
, OSCI_Y
, LCD_WIDTH
, OSCI_HEIGHT
);
505 void splitedit_zoom_in(struct mp3entry
*mp3
)
507 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
508 rb
->lcd_fillrect(OSCI_X
, OSCI_Y
, OSCI_WIDTH
, OSCI_HEIGHT
);
509 rb
->lcd_set_drawmode(DRMODE_SOLID
);
511 rb
->lcd_update_rect(OSCI_X
, OSCI_Y
, LCD_WIDTH
, OSCI_HEIGHT
);
519 void splitedit_zoom_out(struct mp3entry
*mp3
)
521 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
522 rb
->lcd_fillrect(OSCI_X
, OSCI_Y
, LCD_WIDTH
, OSCI_HEIGHT
);
523 rb
->lcd_set_drawmode(DRMODE_SOLID
);
525 rb
->lcd_update_rect(OSCI_X
, OSCI_Y
, LCD_WIDTH
, OSCI_HEIGHT
);
531 * Append part_no to the file name.
533 static void generateFileName(char* file_name
, int part_no
)
535 if (rb
->strlen(file_name
) <MAX_PATH
)
537 int len
= rb
->strlen(file_name
);
538 int ext_len
= rb
->strlen(".mp3");
540 &file_name
[len
- ext_len
],
544 /* shift the extension one position to the right*/
545 for (i
= len
; i
> len
- ext_len
; i
--)
547 file_name
[i
] = file_name
[i
- 1];
549 file_name
[len
- ext_len
] = '0' + part_no
;
553 rb
->splash(0, "wrong extension");
554 rb
->button_get(true);
555 rb
->button_get(true);
560 rb
->splash(0, "name too long");
561 rb
->button_get(true);
562 rb
->button_get(true);
569 * Copy bytes from src to dest while displaying a progressbar.
570 * The files must be already open.
572 static int copy_file(
580 unsigned char *buffer
;
582 ssize_t bytes_read
= 1; /* ensure the for loop is executed */
584 buffer
= rb
->plugin_get_buffer(&buffer_size
);
586 for (i
= 0; i
< bytes
&& bytes_read
> 0; i
+= bytes_read
)
588 ssize_t bytes_written
;
589 unsigned int bytes_to_read
=
590 bytes
- i
> buffer_size
? buffer_size
: bytes
- i
;
591 bytes_read
= rb
->read(src
, buffer
, bytes_to_read
);
592 bytes_written
= rb
->write(dest
, buffer
, bytes_read
);
594 if (bytes_written
< 0) {
595 rb
->splash(0, "Write failed in copy.");
596 rb
->button_get(true);
597 rb
->button_get(true);
601 button
= rb
->button_get(false);
603 if (button
== SPLITEDIT_QUIT
604 #ifdef SPLITEDIT_RC_QUIT
605 || button
== SPLITEDIT_RC_QUIT
:
608 rb
->splash(0, "Aborting copy.");
609 rb
->button_get(true);
610 rb
->button_get(true);
614 rb
->gui_scrollbar_draw(rb
->screens
[SCREEN_MAIN
],0, prg_y
, LCD_WIDTH
,
615 prg_h
, bytes
, 0, i
, HORIZONTAL
);
616 rb
->lcd_update_rect(0, prg_y
, LCD_WIDTH
, prg_h
);
623 * Save the files, if the file_name is not NULL
626 struct mp3entry
*mp3
,
631 int file1
, file2
, src_file
;
632 unsigned int end
= 0;
635 /* Verify that file 1 doesn't exit yet */
636 if (file_name1
!= NULL
)
638 file1
= rb
->open(file_name1
, O_RDONLY
);
642 rb
->splash(0, "File 1 exists. Please rename.");
643 rb
->button_get(true);
644 rb
->button_get(true);
649 /* Verify that file 2 doesn't exit yet */
650 if (file_name2
!= NULL
)
652 file2
= rb
->open(file_name2
, O_RDONLY
);
656 rb
->splash(0, "File 2 exists. Please rename.");
657 rb
->button_get(true);
658 rb
->button_get(true);
663 /* find the file position of the split point */
665 rb
->audio_ff_rewind(splittime
);
668 end
= rb
->audio_get_file_pos();
670 /* open the source file */
671 src_file
= rb
->open(mp3
->path
, O_RDONLY
);
677 unsigned long last_header
= rb
->mpeg_get_last_header();
679 rb
->lcd_getstringsize("M", &x
, &y
);
681 /* Find the next frame boundary */
682 rb
->lseek(src_file
, end
, SEEK_SET
);
683 rb
->find_next_frame(src_file
, &offset
, 8000, last_header
);
684 rb
->lseek(src_file
, 0, SEEK_SET
);
687 /* write the file 1 */
688 if (file_name1
!= NULL
)
690 file1
= rb
->open (file_name1
, O_WRONLY
| O_CREAT
, 0666);
693 int rc
= copy_file(file1
, src_file
, end
, y
*2 + 1, y
-1);
694 close_stat
= rb
->close(file1
);
698 rb
->splashf(0, "failed closing file1: error %d", close_stat
);
699 rb
->button_get(true);
700 rb
->button_get(true);
702 /* If there was an error, cleanup */
704 rb
->remove(file_name1
);
710 rb
->splashf(0, "Can't write File1: error %d", file1
);
711 rb
->button_get(true);
712 rb
->button_get(true);
716 /* if file1 hasn't been written we're not at the split point yet */
719 if (rb
->lseek(src_file
, end
, SEEK_SET
) < (off_t
)end
)
721 rb
->splashf(0, "Src file to short: error %d", src_file
);
722 rb
->button_get(true);
723 rb
->button_get(true);
727 if (file_name2
!= NULL
)
730 file2
= rb
->open (file_name2
, O_WRONLY
| O_CREAT
, 0666);
733 end
= mp3
->filesize
- end
;
734 int rc
= copy_file(file2
, src_file
, end
, y
* 5 + 1, y
-1);
735 close_stat
= rb
->close(file2
);
739 rb
->splashf(0, "failed: closing file2: error %d",
741 rb
->button_get(true);
742 rb
->button_get(true);
744 /* If there was an error, cleanup */
746 rb
->remove(file_name2
);
752 rb
->splashf(0, "Can't write File2: error %d", file2
);
753 rb
->button_get(true);
754 rb
->button_get(true);
759 close_stat
= rb
->close(src_file
);
762 rb
->splashf(0, "failed: closing src: error %d", close_stat
);
763 rb
->button_get(true);
764 rb
->button_get(true);
769 rb
->splash(0, "Source file not found");
770 rb
->button_get(true);
771 rb
->button_get(true);
781 * Let the user choose which file to save with which name
783 static void save_editor(struct mp3entry
*mp3
, int splittime
)
785 bool exit_request
= false;
787 int button
= BUTTON_NONE
;
788 char part1_name
[MAX_PATH
];
789 char part2_name
[MAX_PATH
];
790 bool part1_save
= true;
791 bool part2_save
= true;
793 /* file name for left part */
794 rb
->strlcpy(part1_name
, mp3
->path
, MAX_PATH
);
795 generateFileName(part1_name
, 1);
797 /* file name for right part */
798 rb
->strlcpy(part2_name
, mp3
->path
, MAX_PATH
);
799 generateFileName(part2_name
, 2);
801 while (!exit_request
)
804 rb
->lcd_clear_display();
807 rb
->lcd_puts_style(0, 0, "Save part 1?", choice
== SE_PART1_SAVE
);
808 rb
->lcd_puts(13, 0, part1_save
?"yes":"no");
810 /* trim to display the filename without path */
811 for (pos
= rb
->strlen(part1_name
); pos
> 0; pos
--)
813 if (part1_name
[pos
] == '/')
819 rb
->lcd_puts_scroll_style(0, 1,
820 &part1_name
[pos
], choice
== SE_PART1_NAME
);
823 rb
->lcd_puts_style(0, 3, "Save part 2?", choice
== SE_PART2_SAVE
);
824 rb
->lcd_puts(13, 3, part2_save
?"yes":"no");
826 /* trim to display the filename without path */
827 for (pos
= rb
->strlen(part2_name
); pos
> 0; pos
--)
829 if (part2_name
[pos
] == '/')
835 rb
->lcd_puts_scroll_style(0, 4,
836 &part2_name
[pos
], choice
== SE_PART2_NAME
);
839 rb
->lcd_puts_style(0, 6, "Save", choice
== SE_SAVE
);
844 button
= rb
->button_get(true);
848 choice
= (choice
+ SE_COUNT
- 1) % SE_COUNT
;
852 choice
= (choice
+ 1) % SE_COUNT
;
855 case SPLITEDIT_MENU_RUN
:
861 part1_save
= !part1_save
;
865 rb
->kbd_input(part1_name
, MAX_PATH
);
869 part2_save
= !part2_save
;
873 rb
->kbd_input(part2_name
, MAX_PATH
);
877 rb
->lcd_stop_scroll();
878 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
879 rb
->lcd_fillrect(0, 6*8, LCD_WIDTH
, LCD_HEIGHT
);
880 rb
->lcd_set_drawmode(DRMODE_SOLID
);
884 part1_save
?part1_name
:NULL
,
885 part2_save
?part2_name
:NULL
,
889 /* if something failed the user may go on choosing */
897 #ifdef SPLITEDIT_RC_QUIT
898 case SPLITEDIT_RC_QUIT
:
905 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
907 splitedit_exit_code
= PLUGIN_USB_CONNECTED
;
916 * The main loop of the editor
918 unsigned long splitedit_editor(struct mp3entry
* mp3_to_split
,
919 unsigned int split_time
,
922 int button
= BUTTON_NONE
;
923 int lastbutton
= BUTTON_NONE
;
924 struct mp3entry
*mp3
= mp3_to_split
;
925 unsigned int last_elapsed
= 0;
926 int lastx
= OSCI_X
+ (OSCI_WIDTH
/ 2);
931 /*unsigned short scheme = SCHEME_SPLIT_EDITOR;*/
932 bool exit_request
= false;
933 set_range_by_time(mp3
, split_time
, range
);
934 splitedit_set_loop_mode(LOOP_MODE_ALL
);
937 /*while (scheme != SCHEME_RETURN) {*/
938 while (!exit_request
)
940 unsigned int elapsed
;
944 elapsed
= mp3
->elapsed
;
945 x
= time_to_xpos(elapsed
);
947 /* are we still in the zoomed range? */
948 if (elapsed
> play_start
&& elapsed
< play_end
)
950 /* read volume info */
951 unsigned short volume
;
952 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
953 volume
= rb
->mas_codec_readreg(0x0c);
954 volume
+= rb
->mas_codec_readreg(0x0d);
956 volume
= rb
->peak_meter_scale_value(volume
, OSCI_HEIGHT
);
958 volume
= OSCI_HEIGHT
/ 2;
961 /* update osci_buffer */
962 if (osci_valid
|| lastx
== x
)
964 int index
= x
- OSCI_X
;
965 osci_buffer
[index
] = MAX(osci_buffer
[index
], volume
);
970 osci_buffer
[x
- OSCI_X
] = volume
;
971 for (i
= lastx
+ 1; i
< x
; i
++)
973 osci_buffer
[i
- OSCI_X
] = 0;
978 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
979 rb
->lcd_fillrect(lastx
+ 1, OSCI_Y
, x
- lastx
, OSCI_HEIGHT
);
980 rb
->lcd_set_drawmode(DRMODE_SOLID
);
982 if (osci_buffer
[x
- OSCI_X
] > 0)
985 for (i
= lastx
+1; i
<= x
; i
++)
989 i
, OSCI_Y
+ OSCI_HEIGHT
- 1,
990 OSCI_Y
+ OSCI_HEIGHT
- osci_buffer
[i
- OSCI_X
]-1
995 /* mark the current position */
998 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
999 rb
->lcd_fillrect(lastx
, OSCI_Y
, 1, OSCI_HEIGHT
);
1000 rb
->lcd_fillrect(x
, OSCI_Y
, 1, OSCI_HEIGHT
);
1001 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1004 /* mark the split point */
1005 if ((x
> split_x
- 2) && (lastx
< split_x
+ 3))
1007 if ((lastx
< split_x
) && (x
>= split_x
))
1009 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
1012 split_x
, OSCI_Y
+ 2,
1015 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1017 rb
->lcd_hline(split_x
-2, split_x
+ 2, OSCI_Y
);
1018 rb
->lcd_hline(split_x
-1, split_x
+1,OSCI_Y
+1);
1024 rb
->lcd_update_rect(lastx
, OSCI_Y
, x
-lastx
+1, OSCI_HEIGHT
);
1031 OSCI_X
+ OSCI_WIDTH
- lastx
, OSCI_HEIGHT
1033 rb
->lcd_update_rect(0, OSCI_Y
, x
+ 1, OSCI_HEIGHT
);
1039 /* we're not in the zoom range -> rewind */
1042 if (elapsed
>= play_end
)
1044 switch (splitedit_get_loop_mode())
1046 unsigned int range_width
;
1051 rb
->audio_ff_rewind(range_start
);
1052 #if (CONFIG_STORAGE & STORAGE_MMC)
1053 /* MMC is slow - wait some time to allow track reload to finish */
1055 if (mp3
->elapsed
> play_end
) /* reload in progress */
1056 rb
->splash(10*HZ
, "Wait - reloading");
1061 case LOOP_MODE_FROM
:
1063 rb
->audio_ff_rewind(xpos_to_time(split_x
));
1064 #if (CONFIG_STORAGE & STORAGE_MMC)
1065 /* MMC is slow - wait some time to allow track reload to finish */
1067 if (mp3
->elapsed
> play_end
) /* reload in progress */
1068 rb
->splash(10*HZ
, "Wait - reloading");
1073 case LOOP_MODE_FREE
:
1074 range_width
= range_end
- range_start
;
1075 set_range_by_time(mp3
,
1076 range_end
+ range_width
/ 2, range_width
);
1078 /* play_end und play_start anpassen */
1079 splitedit_set_loop_mode(LOOP_MODE_FREE
);
1080 rb
->memset(osci_buffer
, 0, sizeof osci_buffer
);
1088 button
= rb
->button_get(false);
1091 /* here the evaluation of the key scheme starts.
1092 All functions the user triggers are called from
1093 within execute_scheme */
1094 /* key_scheme_execute(button, &scheme); */
1097 case SPLITEDIT_PLAY
:
1098 #ifdef SPLITEDIT_PLAY_PRE
1099 if (lastbutton
!= SPLITEDIT_PLAY_PRE
)
1103 rb
->audio_ff_rewind(xpos_to_time(split_x
));
1108 splitedit_zoom_in(mp3
);
1109 lastx
= time_to_xpos(mp3
->elapsed
);
1113 splitedit_zoom_out(mp3
);
1114 lastx
= time_to_xpos(mp3
->elapsed
);
1117 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
1118 #ifdef SPLITEDIT_SPEED100
1119 case SPLITEDIT_SPEED150
:
1120 rb
->sound_set_pitch(150L*PITCH_SPEED_PRECISION
);
1121 splitedit_invalidate_osci();
1124 case SPLITEDIT_SPEED100
:
1125 rb
->sound_set_pitch(PITCH_SPEED_100
);
1126 splitedit_invalidate_osci();
1129 case SPLITEDIT_SPEED50
:
1130 rb
->sound_set_pitch(50L*PITCH_SPEED_PRECISION
);
1131 splitedit_invalidate_osci();
1137 case BUTTON_LEFT
| BUTTON_REPEAT
:
1138 if (splitedit_get_split_x() > OSCI_X
+ 2)
1140 splitedit_set_split_x(splitedit_get_split_x() - 1);
1145 lastx
= time_to_xpos(mp3
->elapsed
);
1150 case BUTTON_RIGHT
| BUTTON_REPEAT
:
1151 if (splitedit_get_split_x() < OSCI_X
+ OSCI_WIDTH
-3)
1153 splitedit_set_split_x(splitedit_get_split_x() + 1);
1158 lastx
= time_to_xpos(mp3
->elapsed
);
1162 case SPLITEDIT_SAVE
:
1163 save_editor(mp3
, xpos_to_time(split_x
));
1164 rb
->lcd_clear_display();
1166 update_timebar(mp3
);
1170 case SPLITEDIT_LOOP_MODE
:
1171 splitedit_set_loop_mode(splitedit_get_loop_mode() + 1);
1175 case SPLITEDIT_SCALE
:
1176 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
1177 rb
->peak_meter_set_use_dbfs(!rb
->peak_meter_get_use_dbfs());
1179 splitedit_invalidate_osci();
1183 #ifdef SPLITEDIT_RC_QUIT
1184 case SPLITEDIT_RC_QUIT
:
1186 case SPLITEDIT_QUIT
:
1187 exit_request
= true;
1191 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
1193 splitedit_exit_code
= PLUGIN_USB_CONNECTED
;
1194 exit_request
= true;
1199 if (button
!= BUTTON_NONE
)
1200 lastbutton
= button
;
1202 if (validation_start
== ~(unsigned int)0)
1204 if (elapsed
< range_end
&& elapsed
> range_start
)
1206 validation_start
= elapsed
;
1210 int endx
= time_to_xpos(range_end
);
1211 validation_start
= xpos_to_time(endx
- 2);
1213 last_elapsed
= elapsed
+ 1;
1217 if ((last_elapsed
<= validation_start
) &&
1218 (elapsed
> validation_start
))
1223 last_elapsed
= elapsed
;
1227 if (mp3
!= rb
->audio_current_track())
1229 struct mp3entry
*new_mp3
= rb
->audio_current_track();
1230 if (rb
->strncasecmp(path_mp3
, new_mp3
->path
,
1233 rb
->splash(0, "Abort due to file change");
1234 rb
->button_get(true);
1235 rb
->button_get(true);
1236 exit_request
= true;
1242 rb
->audio_flush_and_reload_tracks();
1243 rb
->audio_ff_rewind(range_start
);
1248 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
1249 #ifdef SPLITEDIT_SPEED100
1250 rb
->sound_set_pitch(1000); /* make sure to reset pitch */
1258 enum plugin_status
plugin_start(const void* parameter
)
1260 struct mp3entry
* mp3
;
1263 rb
->lcd_clear_display();
1265 mp3
= rb
->audio_current_track();
1268 if (rb
->audio_status() & AUDIO_STATUS_PAUSE
)
1272 splitedit_editor(mp3
, mp3
->elapsed
, MIN_RANGE_SIZE
* 8);
1276 rb
->splash(0, "Play or pause a mp3 file first.");
1277 rb
->button_get(true);
1278 rb
->button_get(true);
1280 return splitedit_exit_code
;