summaryrefslogtreecommitdiff
path: root/apps/plugins/splitedit.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/splitedit.c')
-rw-r--r--apps/plugins/splitedit.c1231
1 files changed, 0 insertions, 1231 deletions
diff --git a/apps/plugins/splitedit.c b/apps/plugins/splitedit.c
deleted file mode 100644
index b698e2e18a..0000000000
--- a/apps/plugins/splitedit.c
+++ /dev/null
@@ -1,1231 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Philipp Pertermann
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "plugin.h"
23
24
25
26/* variable button definitions */
27#if CONFIG_KEYPAD == IRIVER_H100_PAD
28#define SPLITEDIT_QUIT BUTTON_OFF
29#define SPLITEDIT_PLAY BUTTON_ON
30#define SPLITEDIT_SAVE BUTTON_SELECT
31#define SPLITEDIT_LOOP_MODE BUTTON_MODE
32#define SPLITEDIT_SCALE (BUTTON_REC | BUTTON_UP)
33#define SPLITEDIT_SPEED50 (BUTTON_REC | BUTTON_LEFT)
34#define SPLITEDIT_SPEED100 (BUTTON_REC | BUTTON_DOWN)
35#define SPLITEDIT_SPEED150 (BUTTON_REC | BUTTON_RIGHT)
36#define SPLITEDIT_MENU_RUN BUTTON_RIGHT
37
38#elif (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) || \
39 (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD)
40#define SPLITEDIT_QUIT (BUTTON_REC | BUTTON_REW)
41#define SPLITEDIT_PLAY (BUTTON_REC | BUTTON_FFWD)
42#define SPLITEDIT_SAVE BUTTON_FFWD
43#define SPLITEDIT_LOOP_MODE BUTTON_REW
44#define SPLITEDIT_SCALE BUTTON_UP
45#define SPLITEDIT_SPEED50 BUTTON_LEFT
46#define SPLITEDIT_SPEED100 BUTTON_DOWN
47#define SPLITEDIT_SPEED150 BUTTON_RIGHT
48#define SPLITEDIT_MENU_RUN BUTTON_PLAY
49
50#define SPLITEDIT_RC_QUIT BUTTON_RC_STOP
51#endif
52
53#define BMPHEIGHT 7
54#define BMPWIDTH 13
55unsigned char LOOP_BMP[][13] =
56{
57 {0xfc,0x00,0x10,0x11,0x93,0x7f,0x13,0x11,0x7c,0x38,0x10,0x00,0x7c}, /*ALL */
58 {0x81,0x03,0x7f,0x03,0x91,0x10,0x10,0x10,0x7c,0x38,0x10,0x00,0x7c}, /*FROM*/
59 {0xfc,0x00,0x10,0x10,0x90,0x10,0x7c,0x38,0x11,0x03,0x7f,0x03,0x01}, /*TO */
60 {0x80,0x10,0x10,0x11,0x93,0x7f,0x13,0x11,0x10,0x7c,0x38,0x10,0x00}, /*FREE*/
61};
62
63unsigned char CUT_BMP[] =
64{
65 0xc1,0x63,0x63,0x36,0xb6,0x1c,0x1c,0x36,0x77,0x55,0x55,0x55,0x32,
66};
67
68unsigned char SCALE_BMP[][13] =
69{
70 {0x80,0x06,0x49,0x66,0xb0,0x18,0x0c,0x06,0x33,0x49,0x30,0x00,0x00}, /*lin*/
71 {0x80,0x30,0x78,0x48,0xff,0x7f,0x00,0x7f,0x7f,0x48,0x78,0x30,0x00}, /*db*/
72};
73
74#define TIMEBAR_Y 9
75#define TIMEBAR_HEIGHT 4
76
77#define OSCI_X 0
78#define OSCI_Y (TIMEBAR_Y + TIMEBAR_HEIGHT + 1)
79#define OSCI_WIDTH LCD_WIDTH
80#define OSCI_HEIGHT (LCD_HEIGHT - BMPHEIGHT - OSCI_Y - 1)
81
82/* Indices of the menu items in the save editor, see save_editor */
83#define SE_PART1_SAVE 0
84#define SE_PART1_NAME 1
85#define SE_PART2_SAVE 2
86#define SE_PART2_NAME 3
87#define SE_SAVE 4
88#define SE_COUNT 5
89
90/* contains the file name of the song that is to be split */
91static char path_mp3[MAX_PATH];
92
93/* Exit code of this plugin */
94static enum plugin_status splitedit_exit_code = PLUGIN_OK;
95
96/* The range in time that the displayed aerea comprises */
97static unsigned int range_start = 0;
98static unsigned int range_end = 0;
99
100/* The range in time that is being looped */
101static unsigned int play_start = 0;
102static unsigned int play_end = 0;
103
104/* Point in time (pixel) at which the split mark is set */
105static int split_x = OSCI_X + (OSCI_WIDTH / 2);
106
107/* Contains the peak values */
108static unsigned char osci_buffer[OSCI_WIDTH];
109
110/* if true peak values from a previous loop are only overwritten
111 if the new value is greater than the old value */
112static bool osci_valid = false;
113
114/**
115 * point in time from which on the osci_buffer is invalid
116 * if set to ~(unsigned int)0 the entire osci_buffer is invalid
117 */
118static unsigned int validation_start = ~(unsigned int)0;
119
120/* all the visible aerea is looped */
121#define LOOP_MODE_ALL 0
122
123/* loop starts at split point, ends at right visible border */
124#define LOOP_MODE_FROM 1
125
126/* loop start at left visible border, ends at split point */
127#define LOOP_MODE_TO 2
128
129/* let the song play without looping */
130#define LOOP_MODE_FREE 3
131
132/* see LOOP_MODE_XXX constants vor valid values */
133static int loop_mode = LOOP_MODE_FREE;
134
135/* minimal allowed timespan (ms) of the visible (and looped) aerea*/
136#define MIN_RANGE_SIZE 1000
137
138/* Format time into buf.
139 *
140 * buf - buffer to format to.
141 * buf_size - size of buffer.
142 * time - time to format, in milliseconds.
143 */
144static void format_time_ms(char* buf, int buf_size, int time)
145{
146 rb->snprintf(buf, buf_size, "%d:%02d:%03d", time / 60000,
147 time % 60000 / 1000, (time % 60000) % 1000);
148}
149
150/**
151 * converts screen coordinate (pixel) to time (ms)
152 */
153static int xpos_to_time(int xpos)
154{
155 int retval = 0;
156 int range = range_end - range_start;
157 retval = range_start + (((xpos - OSCI_X) * range) / OSCI_WIDTH);
158 return retval;
159}
160
161/**
162 * Converts time (ms) to screen coordinates (pixel).
163 */
164static int time_to_xpos(unsigned int time)
165{
166 int retval = OSCI_X;
167
168 /* clip the range */
169 if (time < range_start)
170 {
171 retval = OSCI_X;
172 }
173 else
174 if (time >= range_end)
175 {
176 retval = OSCI_X + OSCI_WIDTH;
177 }
178
179 /* do the calculation */
180 else
181 {
182 int range = range_end - range_start;
183 retval = OSCI_X + ((time - range_start) * OSCI_WIDTH) / range ;
184 }
185 return retval;
186}
187
188/**
189 * Updates the display of the textual data only.
190 */
191static void update_data(void)
192{
193 char buf[20];
194 char timebuf[10];
195 int w, h;
196
197 /* split point */
198 format_time_ms(timebuf, sizeof timebuf, xpos_to_time(split_x));
199 rb->snprintf(buf, sizeof buf, "Split at: %s", timebuf);
200
201 rb->lcd_getstringsize(buf, &w, &h);
202
203 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
204 rb->lcd_fillrect(0, 0, LCD_WIDTH, h);
205 rb->lcd_set_drawmode(DRMODE_SOLID);
206 rb->lcd_puts(0, 0, buf);
207 rb->lcd_update_rect(0, 0, LCD_WIDTH, h);
208}
209
210/**
211 * Displays which part of the song is visible
212 * in the osci.
213 */
214static void update_timebar(struct mp3entry *mp3)
215{
216 rb->gui_scrollbar_draw
217 (
218 rb->screens[SCREEN_MAIN],0, TIMEBAR_Y, LCD_WIDTH, TIMEBAR_HEIGHT,
219 mp3->length, range_start, range_end,
220 HORIZONTAL
221 );
222 rb->lcd_update_rect(0, TIMEBAR_Y, LCD_WIDTH, TIMEBAR_HEIGHT);
223}
224
225/**
226 * Marks the entire area of the osci buffer invalid.
227 * It will be drawn with new values in the next loop.
228 */
229static void splitedit_invalidate_osci(void)
230{
231 osci_valid = false;
232 validation_start = ~(unsigned int)0;
233}
234
235/**
236 * Returns the loop mode. See the LOOP_MODE_XXX constants above.
237 */
238static int splitedit_get_loop_mode(void)
239{
240 return loop_mode;
241}
242
243/**
244 * Updates the icons that display the Fn key hints.
245 */
246static void update_icons(void)
247{
248 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
249 rb->lcd_fillrect(0, LCD_HEIGHT - BMPHEIGHT, LCD_WIDTH, BMPHEIGHT);
250 rb->lcd_set_drawmode(DRMODE_SOLID);
251
252 /* The CUT icon */
253 rb->lcd_mono_bitmap(CUT_BMP,
254 LCD_WIDTH / 3 / 2 - BMPWIDTH / 2, LCD_HEIGHT - BMPHEIGHT,
255 BMPWIDTH, BMPHEIGHT);
256
257 /* The loop mode icon */
258 rb->lcd_mono_bitmap(LOOP_BMP[splitedit_get_loop_mode()],
259 LCD_WIDTH/3 + LCD_WIDTH/3 / 2 - BMPWIDTH/2, LCD_HEIGHT - BMPHEIGHT,
260 BMPWIDTH, BMPHEIGHT);
261
262 {
263 static int idx;
264 if (idx < 0 || idx > 1) idx = 0;
265 idx = 1 - idx;
266 rb->lcd_mono_bitmap(SCALE_BMP[idx],
267 2 *LCD_WIDTH/3 + LCD_WIDTH/3 / 2 - BMPWIDTH/2, LCD_HEIGHT - BMPHEIGHT,
268 BMPWIDTH, BMPHEIGHT);
269 }
270
271 rb->lcd_update_rect(0, LCD_HEIGHT - BMPHEIGHT, LCD_WIDTH, BMPHEIGHT);
272}
273
274/**
275 * Sets the loop mode. See the LOOP_MODE_XXX constants above.
276 */
277static void splitedit_set_loop_mode(int mode)
278{
279 int old_loop_mode = loop_mode;
280 /* range restriction */
281 loop_mode = mode % (LOOP_MODE_FREE + 1);
282 switch (loop_mode)
283 {
284 case LOOP_MODE_ALL:
285 play_start = range_start;
286 play_end = range_end;
287 break;
288
289 case LOOP_MODE_FROM:
290 play_start = xpos_to_time(split_x);
291 play_end = range_end;
292 break;
293
294 case LOOP_MODE_TO:
295 play_start = range_start;
296 play_end = xpos_to_time(split_x);
297 break;
298
299 case LOOP_MODE_FREE:
300 /* play_start is used when the song plays beyond its end */
301 play_start = range_start;
302 play_end = range_end;
303 break;
304 }
305
306 if (loop_mode != old_loop_mode)
307 {
308 update_icons();
309 }
310}
311
312/**
313 * Readraws the osci without clear.
314 */
315static void redraw_osci(void)
316{
317 int x;
318 for (x = 0; x < OSCI_WIDTH; x++)
319 {
320 if (osci_buffer[x] > 0)
321 {
322 rb->lcd_vline
323 (
324 OSCI_X + x, OSCI_Y + OSCI_HEIGHT - 1,
325 OSCI_Y + OSCI_HEIGHT - osci_buffer[x] - 1
326 );
327 }
328 }
329}
330
331/**
332 * Sets the range of time in which the user can finetune the split
333 * point. The split point is the center of the time range.
334 */
335static void set_range_by_time(
336 struct mp3entry *mp3,
337 unsigned int split_time,
338 unsigned int range)
339{
340 if (mp3 != NULL)
341 {
342 if (range < MIN_RANGE_SIZE)
343 {
344 range = MIN_RANGE_SIZE;
345 }
346 range_start = (split_time > range / 2) ? (split_time - range / 2) : 0;
347 range_end = MIN(range_start + range, mp3->length);
348 split_x = time_to_xpos(split_time);
349
350 splitedit_invalidate_osci();
351
352 /* this sets the play_start / play_end */
353 splitedit_set_loop_mode(splitedit_get_loop_mode());
354
355 update_data();
356 update_timebar(mp3);
357 }
358}
359
360/**
361 * Set the split point in screen coordinates
362 */
363static void splitedit_set_split_x(int newx)
364{
365 int minx = split_x - 2 > 0 ? split_x - 2: 0;
366
367 /* remove old split point from screen, only if moved */
368 if (split_x != newx)
369 {
370 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
371 rb->lcd_fillrect(minx, OSCI_Y, 5, 1);
372 rb->lcd_fillrect(split_x-1 > 0 ? split_x - 1: 0, OSCI_Y + 1, 3, 1);
373 rb->lcd_fillrect(split_x, OSCI_Y + 2, 1, OSCI_HEIGHT - 2);
374 rb->lcd_set_drawmode(DRMODE_SOLID);
375 rb->lcd_update_rect(minx, OSCI_Y, 5, OSCI_HEIGHT);
376 }
377
378 if (newx >= OSCI_X && newx < OSCI_X + OSCI_WIDTH)
379 {
380 split_x = newx;
381 /* in LOOP_FROM / LOOP_TO modes play_start /play_end must be updated */
382 splitedit_set_loop_mode(splitedit_get_loop_mode());
383
384 /* display new split time */
385 update_data();
386 }
387
388 /* display new split point */
389 minx = split_x - 2 > 0 ? split_x - 2: 0;
390 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
391 rb->lcd_fillrect(minx, OSCI_Y, 5, 1);
392 rb->lcd_fillrect(split_x - 1 > 0 ? split_x - 1: 0, OSCI_Y + 1, 3, 1);
393 rb->lcd_fillrect(split_x, OSCI_Y + 2, 1, OSCI_HEIGHT - 2);
394 rb->lcd_set_drawmode(DRMODE_SOLID);
395 rb->lcd_update_rect(minx, OSCI_Y, 5, OSCI_HEIGHT);
396}
397
398/**
399 * returns the split point in screen coordinates
400 */
401static int splitedit_get_split_x(void)
402{
403 return split_x;
404}
405
406/**
407 * Clears the osci area and redraws it
408 */
409static void update_osci(void)
410{
411 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
412 rb->lcd_fillrect(OSCI_X, OSCI_Y, OSCI_WIDTH, OSCI_HEIGHT);
413 rb->lcd_set_drawmode(DRMODE_SOLID);
414 redraw_osci();
415 splitedit_set_split_x(splitedit_get_split_x());
416 rb->lcd_update_rect(OSCI_X, OSCI_Y, OSCI_WIDTH, OSCI_HEIGHT);
417}
418
419/**
420 * Zooms the visable and loopable range by the factor
421 * (counter / denominator). The split point is used as
422 * center point of the new selected range.
423 */
424static void zoom(struct mp3entry *mp3, int counter, int denominator)
425{
426 unsigned char oldbuf[OSCI_WIDTH];
427 int oldrange = range_end - range_start;
428 int range = oldrange * counter / denominator;
429 int i;
430 int oldindex;
431 int oldsplitx;
432 int splitx;
433 int split;
434
435 /* for stretching / shrinking a second buffer is needed */
436 rb->memcpy(&oldbuf, &osci_buffer, sizeof osci_buffer);
437
438 /* recalculate the new range and split point */
439 oldsplitx = split_x;
440 split = xpos_to_time(split_x);
441
442 set_range_by_time(mp3, split, range);
443 range = range_end - range_start;
444
445 splitx = time_to_xpos(split);
446
447 /* strech / shrink the existing osci buffer */
448 for (i = 0; i < OSCI_WIDTH; i++)
449 {
450 /* oldindex = (i + OSCI_X - splitx) * range / oldrange + oldsplitx ;*/
451 oldindex = (i*range / oldrange) + oldsplitx - (splitx*range /oldrange);
452 if (oldindex >= 0 && oldindex < OSCI_WIDTH)
453 {
454 osci_buffer[i] = oldbuf[oldindex];
455 }
456 else
457 {
458 osci_buffer[i] = 0;
459 }
460 }
461
462 splitx = time_to_xpos(split);
463 splitedit_set_split_x(splitx);
464 splitedit_invalidate_osci();
465
466}
467
468static void scroll(struct mp3entry *mp3)
469{
470 zoom(mp3, 1, 1);
471 rb->lcd_update_rect(OSCI_X, OSCI_Y, LCD_WIDTH, OSCI_HEIGHT);
472 update_osci();
473 update_data();
474}
475
476/**
477 * Zooms in by 3/4
478 */
479static void splitedit_zoom_in(struct mp3entry *mp3)
480{
481 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
482 rb->lcd_fillrect(OSCI_X, OSCI_Y, OSCI_WIDTH, OSCI_HEIGHT);
483 rb->lcd_set_drawmode(DRMODE_SOLID);
484 zoom(mp3, 3, 4);
485 rb->lcd_update_rect(OSCI_X, OSCI_Y, LCD_WIDTH, OSCI_HEIGHT);
486 update_osci();
487 update_data();
488}
489
490/**
491 * Zooms out by 4/3
492 */
493static void splitedit_zoom_out(struct mp3entry *mp3)
494{
495 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
496 rb->lcd_fillrect(OSCI_X, OSCI_Y, LCD_WIDTH, OSCI_HEIGHT);
497 rb->lcd_set_drawmode(DRMODE_SOLID);
498 zoom(mp3, 4, 3);
499 rb->lcd_update_rect(OSCI_X, OSCI_Y, LCD_WIDTH, OSCI_HEIGHT);
500 update_osci();
501 update_data();
502}
503
504/**
505 * Append part_no to the file name.
506 */
507static void generateFileName(char* file_name, int part_no)
508{
509 if (rb->strlen(file_name) <MAX_PATH)
510 {
511 int len = rb->strlen(file_name);
512 int ext_len = rb->strlen(".mp3");
513 if (rb->strcasecmp(
514 &file_name[len - ext_len],
515 ".mp3") == 0)
516 {
517 int i = 0;
518 /* shift the extension one position to the right*/
519 for (i = len; i > len - ext_len; i--)
520 {
521 file_name[i] = file_name[i - 1];
522 }
523 file_name[len - ext_len] = '0' + part_no;
524 }
525 else
526 {
527 rb->splash(0, "wrong extension");
528 rb->button_get(true);
529 rb->button_get(true);
530 }
531 }
532 else
533 {
534 rb->splash(0, "name too long");
535 rb->button_get(true);
536 rb->button_get(true);
537
538 }
539
540}
541
542/**
543 * Copy bytes from src to dest while displaying a progressbar.
544 * The files must be already open.
545 */
546static int copy_file(
547 int dest,
548 int src,
549 unsigned int bytes,
550 int prg_y,
551 int prg_h)
552{
553 long button;
554 unsigned char *buffer;
555 unsigned int i = 0;
556 ssize_t bytes_read = 1; /* ensure the for loop is executed */
557 size_t buffer_size;
558 buffer = rb->plugin_get_buffer(&buffer_size);
559
560 for (i = 0; i < bytes && bytes_read > 0; i += bytes_read)
561 {
562 ssize_t bytes_written;
563 unsigned int bytes_to_read =
564 bytes - i > buffer_size ? buffer_size : bytes - i;
565 bytes_read = rb->read(src, buffer, bytes_to_read);
566 bytes_written = rb->write(dest, buffer, bytes_read);
567
568 if (bytes_written < 0) {
569 rb->splash(0, "Write failed in copy.");
570 rb->button_get(true);
571 rb->button_get(true);
572 return -1;
573 }
574
575 button = rb->button_get(false);
576
577 if (button == SPLITEDIT_QUIT
578#ifdef SPLITEDIT_RC_QUIT
579 || button == SPLITEDIT_RC_QUIT:
580#endif
581 ) {
582 rb->splash(0, "Aborting copy.");
583 rb->button_get(true);
584 rb->button_get(true);
585 return -1;
586 }
587
588 rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN],0, prg_y, LCD_WIDTH,
589 prg_h, bytes, 0, i, HORIZONTAL);
590 rb->lcd_update_rect(0, prg_y, LCD_WIDTH, prg_h);
591 }
592
593 return 0;
594}
595
596/**
597 * Save the files, if the file_name is not NULL
598 */
599static int save(
600 struct mp3entry *mp3,
601 char *file_name1,
602 char *file_name2,
603 int splittime)
604{
605 int file1, file2, src_file;
606 unsigned int end = 0;
607 int retval = 0;
608
609 /* Verify that file 1 doesn't exit yet */
610 if (file_name1 != NULL)
611 {
612 file1 = rb->open(file_name1, O_RDONLY);
613 if (file1 >= 0)
614 {
615 rb->close(file1);
616 rb->splash(0, "File 1 exists. Please rename.");
617 rb->button_get(true);
618 rb->button_get(true);
619 return -1;
620 }
621 }
622
623 /* Verify that file 2 doesn't exit yet */
624 if (file_name2 != NULL)
625 {
626 file2 = rb->open(file_name2, O_RDONLY);
627 if (file2 >= 0)
628 {
629 rb->close(file2);
630 rb->splash(0, "File 2 exists. Please rename.");
631 rb->button_get(true);
632 rb->button_get(true);
633 return -2;
634 }
635 }
636
637 /* find the file position of the split point */
638 rb->audio_pause();
639 rb->audio_ff_rewind(splittime);
640 rb->yield();
641 rb->yield();
642 end = rb->audio_get_file_pos();
643
644 /* open the source file */
645 src_file = rb->open(mp3->path, O_RDONLY);
646 if (src_file >= 0)
647 {
648 int close_stat = 0;
649 int x, y;
650 long offset;
651 unsigned long last_header = rb->mpeg_get_last_header();
652
653 rb->lcd_getstringsize("M", &x, &y);
654
655 /* Find the next frame boundary */
656 rb->lseek(src_file, end, SEEK_SET);
657 rb->find_next_frame(src_file, &offset, 8000, last_header);
658 rb->lseek(src_file, 0, SEEK_SET);
659 end += offset;
660
661 /* write the file 1 */
662 if (file_name1 != NULL)
663 {
664 file1 = rb->open (file_name1, O_WRONLY | O_CREAT, 0666);
665 if (file1 >= 0)
666 {
667 int rc = copy_file(file1, src_file, end, y*2 + 1, y -1);
668 close_stat = rb->close(file1);
669
670 if (close_stat != 0)
671 {
672 rb->splashf(0, "failed closing file1: error %d", close_stat);
673 rb->button_get(true);
674 rb->button_get(true);
675 } else {
676 /* If there was an error, cleanup */
677 if (rc) {
678 rb->remove(file_name1);
679 }
680 }
681 }
682 else
683 {
684 rb->splashf(0, "Can't write File1: error %d", file1);
685 rb->button_get(true);
686 rb->button_get(true);
687 retval = -1;
688 }
689 }
690 /* if file1 hasn't been written we're not at the split point yet */
691 else
692 {
693 if (rb->lseek(src_file, end, SEEK_SET) < (off_t)end)
694 {
695 rb->splashf(0, "Src file to short: error %d", src_file);
696 rb->button_get(true);
697 rb->button_get(true);
698 }
699 }
700
701 if (file_name2 != NULL)
702 {
703 /* write file 2 */
704 file2 = rb->open (file_name2, O_WRONLY | O_CREAT, 0666);
705 if (file2 >= 0)
706 {
707 end = mp3->filesize - end;
708 int rc = copy_file(file2, src_file, end, y * 5 + 1, y -1);
709 close_stat = rb->close(file2);
710
711 if (close_stat != 0)
712 {
713 rb->splashf(0, "failed: closing file2: error %d",
714 close_stat);
715 rb->button_get(true);
716 rb->button_get(true);
717 } else {
718 /* If there was an error, cleanup */
719 if (rc) {
720 rb->remove(file_name2);
721 }
722 }
723 }
724 else
725 {
726 rb->splashf(0, "Can't write File2: error %d", file2);
727 rb->button_get(true);
728 rb->button_get(true);
729 retval = -2;
730 }
731 }
732
733 close_stat = rb->close(src_file);
734 if (close_stat != 0)
735 {
736 rb->splashf(0, "failed: closing src: error %d", close_stat);
737 rb->button_get(true);
738 rb->button_get(true);
739 }
740 }
741 else
742 {
743 rb->splash(0, "Source file not found");
744 rb->button_get(true);
745 rb->button_get(true);
746 retval = -3;
747 }
748
749 rb->audio_resume();
750
751 return retval;
752}
753
754static void puts_wrapper(int x, int y, const char *str, bool scroll, bool selected)
755{
756 struct line_desc line = LINE_DESC_DEFINIT;
757 struct screen *lcd = rb->screens[SCREEN_MAIN];
758 int w = lcd->getcharwidth();
759 int h = lcd->getcharheight();
760
761 line.scroll = scroll;
762 line.style = selected ? STYLE_INVERT : STYLE_DEFAULT;
763
764 rb->screens[0]->put_line(x * w, y * h, &line, str);
765}
766
767/**
768 * Let the user choose which file to save with which name
769 */
770static void save_editor(struct mp3entry *mp3, int splittime)
771{
772 bool exit_request = false;
773 int choice = 0;
774 int button = BUTTON_NONE;
775 char part1_name [MAX_PATH];
776 char part2_name [MAX_PATH];
777 bool part1_save = true;
778 bool part2_save = true;
779
780 /* file name for left part */
781 rb->strlcpy(part1_name, mp3->path, MAX_PATH);
782 generateFileName(part1_name, 1);
783
784 /* file name for right part */
785 rb->strlcpy(part2_name, mp3->path, MAX_PATH);
786 generateFileName(part2_name, 2);
787
788 while (!exit_request)
789 {
790 int pos;
791 rb->lcd_clear_display();
792
793 /* Save file1? */
794 puts_wrapper(0, 0, "Save part 1?", false, choice == SE_PART1_SAVE);
795 puts_wrapper(7, 0, part1_save?"yes":"no", false, false);
796
797 /* trim to display the filename without path */
798 for (pos = rb->strlen(part1_name); pos > 0; pos--)
799 {
800 if (part1_name[pos] == '/')
801 break;
802 }
803 pos++;
804
805 /* File name 1 */
806 puts_wrapper(0, 1, &part1_name[pos], true, choice == SE_PART1_NAME);
807
808 /* Save file2? */
809 puts_wrapper(0, 3, "Save part 2?", false, choice == SE_PART2_SAVE);
810 puts_wrapper(7, 3, part2_save?"yes":"no", false, false);
811
812 /* trim to display the filename without path */
813 for (pos = rb->strlen(part2_name); pos > 0; pos --)
814 {
815 if (part2_name[pos] == '/')
816 break;
817 }
818 pos++;
819
820 /* File name 2 */
821 puts_wrapper(0, 4, &part2_name[pos], true, choice == SE_PART2_NAME);
822
823 /* Save */
824 puts_wrapper(0, 6, "Save", false, choice == SE_SAVE);
825
826 rb->lcd_update();
827
828
829 button = rb->button_get(true);
830 switch (button)
831 {
832 case BUTTON_UP:
833 choice = (choice + SE_COUNT - 1) % SE_COUNT;
834 break;
835
836 case BUTTON_DOWN:
837 choice = (choice + 1) % SE_COUNT;
838 break;
839
840 case SPLITEDIT_MENU_RUN:
841 switch (choice)
842 {
843 int saved;
844
845 case SE_PART1_SAVE:
846 part1_save = !part1_save;
847 break;
848
849 case SE_PART1_NAME:
850 rb->kbd_input(part1_name, MAX_PATH, NULL);
851 break;
852
853 case SE_PART2_SAVE:
854 part2_save = !part2_save;
855 break;
856
857 case SE_PART2_NAME:
858 rb->kbd_input(part2_name, MAX_PATH, NULL);
859 break;
860
861 case SE_SAVE:
862 rb->lcd_scroll_stop();
863 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
864 rb->lcd_fillrect(0, 6*8, LCD_WIDTH, LCD_HEIGHT);
865 rb->lcd_set_drawmode(DRMODE_SOLID);
866 saved = save
867 (
868 mp3,
869 part1_save?part1_name:NULL,
870 part2_save?part2_name:NULL,
871 splittime
872 );
873
874 /* if something failed the user may go on choosing */
875 if (saved >= 0)
876 {
877 exit_request = true;
878 }
879 break;
880 }
881 break;
882#ifdef SPLITEDIT_RC_QUIT
883 case SPLITEDIT_RC_QUIT:
884#endif
885 case SPLITEDIT_QUIT:
886 exit_request = true;
887 break;
888
889 default:
890 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
891 {
892 splitedit_exit_code = PLUGIN_USB_CONNECTED;
893 exit_request = true;
894 }
895 break;
896 }
897 }
898}
899
900/**
901 * The main loop of the editor
902 */
903static unsigned long splitedit_editor(struct mp3entry * mp3_to_split,
904 unsigned int split_time,
905 unsigned int range)
906{
907 int button = BUTTON_NONE;
908 int lastbutton = BUTTON_NONE;
909 struct mp3entry *mp3 = mp3_to_split;
910 unsigned int last_elapsed = 0;
911 int lastx = OSCI_X + (OSCI_WIDTH / 2);
912 int retval = -1;
913
914 if (mp3 != NULL)
915 {
916 /*unsigned short scheme = SCHEME_SPLIT_EDITOR;*/
917 bool exit_request = false;
918 set_range_by_time(mp3, split_time, range);
919 splitedit_set_loop_mode(LOOP_MODE_ALL);
920 update_icons();
921
922 /*while (scheme != SCHEME_RETURN) {*/
923 while (!exit_request)
924 {
925 unsigned int elapsed ;
926 int x ;
927
928 /* get position */
929 elapsed = mp3->elapsed;
930 x = time_to_xpos(elapsed);
931
932 /* are we still in the zoomed range? */
933 if (elapsed > play_start && elapsed < play_end)
934 {
935 /* read volume info */
936 unsigned short volume;
937 volume = OSCI_HEIGHT / 2;
938
939 /* update osci_buffer */
940 if (osci_valid || lastx == x)
941 {
942 int index = x - OSCI_X;
943 osci_buffer[index] = MAX(osci_buffer[index], volume);
944 }
945 else
946 {
947 int i;
948 osci_buffer[x - OSCI_X] = volume;
949 for (i = lastx + 1; i < x; i++)
950 {
951 osci_buffer[i - OSCI_X] = 0;
952 }
953 }
954
955 /* make room */
956 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
957 rb->lcd_fillrect(lastx + 1, OSCI_Y, x - lastx, OSCI_HEIGHT);
958 rb->lcd_set_drawmode(DRMODE_SOLID);
959 /* draw a value */
960 if (osci_buffer[x - OSCI_X] > 0)
961 {
962 int i;
963 for (i = lastx +1; i <= x; i++)
964 {
965 rb->lcd_vline
966 (
967 i, OSCI_Y + OSCI_HEIGHT - 1,
968 OSCI_Y + OSCI_HEIGHT - osci_buffer[i - OSCI_X]-1
969 );
970 }
971 }
972
973 /* mark the current position */
974 if (lastx != x)
975 {
976 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
977 rb->lcd_fillrect(lastx, OSCI_Y, 1, OSCI_HEIGHT);
978 rb->lcd_fillrect(x, OSCI_Y, 1, OSCI_HEIGHT);
979 rb->lcd_set_drawmode(DRMODE_SOLID);
980 }
981
982 /* mark the split point */
983 if ((x > split_x - 2) && (lastx < split_x + 3))
984 {
985 if ((lastx < split_x) && (x >= split_x))
986 {
987 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
988 rb->lcd_fillrect
989 (
990 split_x, OSCI_Y + 2,
991 1, OSCI_HEIGHT - 2
992 );
993 rb->lcd_set_drawmode(DRMODE_SOLID);
994 }
995 rb->lcd_hline(split_x -2, split_x + 2, OSCI_Y);
996 rb->lcd_hline(split_x-1, split_x +1,OSCI_Y+1);
997 }
998
999 /* make visible */
1000 if (lastx <= x)
1001 {
1002 rb->lcd_update_rect(lastx, OSCI_Y, x-lastx+1, OSCI_HEIGHT);
1003 }
1004 else
1005 {
1006 rb->lcd_update_rect
1007 (
1008 lastx, OSCI_Y,
1009 OSCI_X + OSCI_WIDTH - lastx, OSCI_HEIGHT
1010 );
1011 rb->lcd_update_rect(0, OSCI_Y, x + 1, OSCI_HEIGHT);
1012 }
1013
1014 lastx = x;
1015 }
1016
1017 /* we're not in the zoom range -> rewind */
1018 else
1019 {
1020 if (elapsed >= play_end)
1021 {
1022 switch (splitedit_get_loop_mode())
1023 {
1024 unsigned int range_width;
1025
1026 case LOOP_MODE_ALL:
1027 case LOOP_MODE_TO:
1028 rb->audio_pause();
1029 rb->audio_ff_rewind(range_start);
1030#if (CONFIG_STORAGE & STORAGE_MMC)
1031/* MMC is slow - wait some time to allow track reload to finish */
1032 rb->sleep(HZ/20);
1033 if (mp3->elapsed > play_end) /* reload in progress */
1034 rb->splash(10*HZ, "Wait - reloading");
1035#endif
1036 rb->audio_resume();
1037 break;
1038
1039 case LOOP_MODE_FROM:
1040 rb->audio_pause();
1041 rb->audio_ff_rewind(xpos_to_time(split_x));
1042#if (CONFIG_STORAGE & STORAGE_MMC)
1043/* MMC is slow - wait some time to allow track reload to finish */
1044 rb->sleep(HZ/20);
1045 if (mp3->elapsed > play_end) /* reload in progress */
1046 rb->splash(10*HZ, "Wait - reloading");
1047#endif
1048 rb->audio_resume();
1049 break;
1050
1051 case LOOP_MODE_FREE:
1052 range_width = range_end - range_start;
1053 set_range_by_time(mp3,
1054 range_end + range_width / 2, range_width);
1055
1056 /* play_end und play_start anpassen */
1057 splitedit_set_loop_mode(LOOP_MODE_FREE);
1058 rb->memset(osci_buffer, 0, sizeof osci_buffer);
1059 update_osci();
1060 rb->lcd_update();
1061 break;
1062 }
1063 }
1064 }
1065
1066 button = rb->button_get(false);
1067 rb->yield();
1068
1069 /* here the evaluation of the key scheme starts.
1070 All functions the user triggers are called from
1071 within execute_scheme */
1072 /* key_scheme_execute(button, &scheme); */
1073 switch (button)
1074 {
1075 case SPLITEDIT_PLAY:
1076#ifdef SPLITEDIT_PLAY_PRE
1077 if (lastbutton != SPLITEDIT_PLAY_PRE)
1078 break;
1079#endif
1080 rb->audio_pause();
1081 rb->audio_ff_rewind(xpos_to_time(split_x));
1082 rb->audio_resume();
1083 break;
1084
1085 case BUTTON_UP:
1086 splitedit_zoom_in(mp3);
1087 lastx = time_to_xpos(mp3->elapsed);
1088 break;
1089
1090 case BUTTON_DOWN:
1091 splitedit_zoom_out(mp3);
1092 lastx = time_to_xpos(mp3->elapsed);
1093 break;
1094
1095 case BUTTON_LEFT:
1096 case BUTTON_LEFT | BUTTON_REPEAT:
1097 if (splitedit_get_split_x() > OSCI_X + 2)
1098 {
1099 splitedit_set_split_x(splitedit_get_split_x() - 1);
1100 }
1101 else
1102 {
1103 scroll(mp3);
1104 lastx = time_to_xpos(mp3->elapsed);
1105 }
1106 break;
1107
1108 case BUTTON_RIGHT:
1109 case BUTTON_RIGHT | BUTTON_REPEAT:
1110 if (splitedit_get_split_x() < OSCI_X + OSCI_WIDTH-3)
1111 {
1112 splitedit_set_split_x(splitedit_get_split_x() + 1);
1113 }
1114 else
1115 {
1116 scroll(mp3);
1117 lastx = time_to_xpos(mp3->elapsed);
1118 }
1119 break;
1120
1121 case SPLITEDIT_SAVE:
1122 save_editor(mp3, xpos_to_time(split_x));
1123 rb->lcd_clear_display();
1124 update_osci();
1125 update_timebar(mp3);
1126 update_icons();
1127 break;
1128
1129 case SPLITEDIT_LOOP_MODE:
1130 splitedit_set_loop_mode(splitedit_get_loop_mode() + 1);
1131 update_icons();
1132 break;
1133
1134 case SPLITEDIT_SCALE:
1135 splitedit_invalidate_osci();
1136 update_icons();
1137 break;
1138
1139#ifdef SPLITEDIT_RC_QUIT
1140 case SPLITEDIT_RC_QUIT:
1141#endif
1142 case SPLITEDIT_QUIT:
1143 exit_request = true;
1144 break;
1145
1146 default:
1147 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
1148 {
1149 splitedit_exit_code = PLUGIN_USB_CONNECTED;
1150 exit_request = true;
1151 }
1152 break;
1153
1154 }
1155 if (button != BUTTON_NONE)
1156 lastbutton = button;
1157
1158 if (validation_start == ~(unsigned int)0)
1159 {
1160 if (elapsed < range_end && elapsed > range_start)
1161 {
1162 validation_start = elapsed;
1163 }
1164 else
1165 {
1166 int endx = time_to_xpos(range_end);
1167 validation_start = xpos_to_time(endx - 2);
1168 }
1169 last_elapsed = elapsed + 1;
1170 }
1171 else
1172 {
1173 if ((last_elapsed <= validation_start) &&
1174 (elapsed > validation_start))
1175 {
1176 osci_valid = true;
1177 }
1178
1179 last_elapsed = elapsed;
1180 }
1181 update_data();
1182
1183 if (mp3 != rb->audio_current_track())
1184 {
1185 struct mp3entry *new_mp3 = rb->audio_current_track();
1186 if (rb->strncasecmp(path_mp3, new_mp3->path,
1187 sizeof (path_mp3)))
1188 {
1189 rb->splash(0, "Abort due to file change");
1190 rb->button_get(true);
1191 rb->button_get(true);
1192 exit_request = true;
1193 }
1194 else
1195 {
1196 mp3 = new_mp3;
1197 rb->audio_pause();
1198 rb->audio_flush_and_reload_tracks();
1199 rb->audio_ff_rewind(range_start);
1200 rb->audio_resume();
1201 }
1202 }
1203 }
1204 }
1205 return retval;
1206}
1207
1208enum plugin_status plugin_start(const void* parameter)
1209{
1210 struct mp3entry* mp3;
1211
1212 (void)parameter;
1213 rb->lcd_clear_display();
1214 rb->lcd_update();
1215 mp3 = rb->audio_current_track();
1216 if (mp3 != NULL)
1217 {
1218 if (rb->audio_status() & AUDIO_STATUS_PAUSE)
1219 {
1220 rb->audio_resume();
1221 }
1222 splitedit_editor(mp3, mp3->elapsed, MIN_RANGE_SIZE * 8);
1223 }
1224 else
1225 {
1226 rb->splash(0, "Play or pause a mp3 file first.");
1227 rb->button_get(true);
1228 rb->button_get(true);
1229 }
1230 return splitedit_exit_code;
1231}