diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/export/mpeg.h | 7 | ||||
-rw-r--r-- | firmware/mpeg.c | 582 |
2 files changed, 405 insertions, 184 deletions
diff --git a/firmware/export/mpeg.h b/firmware/export/mpeg.h index 63eecf51db..bbace28ecd 100644 --- a/firmware/export/mpeg.h +++ b/firmware/export/mpeg.h | |||
@@ -32,6 +32,8 @@ | |||
32 | #define MPEG_PLAY_PENDING_THRESHOLD 0x10000 | 32 | #define MPEG_PLAY_PENDING_THRESHOLD 0x10000 |
33 | #define MPEG_PLAY_PENDING_SWAPSIZE 0x10000 | 33 | #define MPEG_PLAY_PENDING_SWAPSIZE 0x10000 |
34 | 34 | ||
35 | #define MPEG_MAX_PRERECORD_SECONDS 30 | ||
36 | |||
35 | /* For ID3 info and VBR header */ | 37 | /* For ID3 info and VBR header */ |
36 | #define MPEG_RESERVED_HEADER_SPACE (4096 + 1500) | 38 | #define MPEG_RESERVED_HEADER_SPACE (4096 + 1500) |
37 | 39 | ||
@@ -89,7 +91,7 @@ void mpeg_record(char *filename); | |||
89 | void mpeg_new_file(char *filename); | 91 | void mpeg_new_file(char *filename); |
90 | void mpeg_set_recording_options(int frequency, int quality, | 92 | void mpeg_set_recording_options(int frequency, int quality, |
91 | int source, int channel_mode, | 93 | int source, int channel_mode, |
92 | bool editable); | 94 | bool editable, int prerecord_time); |
93 | void mpeg_set_recording_gain(int left, int right, bool use_mic); | 95 | void mpeg_set_recording_gain(int left, int right, bool use_mic); |
94 | unsigned long mpeg_recorded_time(void); | 96 | unsigned long mpeg_recorded_time(void); |
95 | unsigned long mpeg_num_recorded_bytes(void); | 97 | unsigned long mpeg_num_recorded_bytes(void); |
@@ -123,7 +125,8 @@ void mpeg_error_clear(void); | |||
123 | #define MPEG_STATUS_PLAY 1 | 125 | #define MPEG_STATUS_PLAY 1 |
124 | #define MPEG_STATUS_PAUSE 2 | 126 | #define MPEG_STATUS_PAUSE 2 |
125 | #define MPEG_STATUS_RECORD 4 | 127 | #define MPEG_STATUS_RECORD 4 |
126 | #define MPEG_STATUS_ERROR 8 | 128 | #define MPEG_STATUS_PRERECORD 8 |
129 | #define MPEG_STATUS_ERROR 16 | ||
127 | 130 | ||
128 | #define MPEGERR_DISK_FULL 1 | 131 | #define MPEGERR_DISK_FULL 1 |
129 | 132 | ||
diff --git a/firmware/mpeg.c b/firmware/mpeg.c index 80e871597e..43da221800 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c | |||
@@ -44,6 +44,7 @@ extern void bitswap(unsigned char *data, int length); | |||
44 | #ifdef HAVE_MAS3587F | 44 | #ifdef HAVE_MAS3587F |
45 | static void init_recording(void); | 45 | static void init_recording(void); |
46 | static void init_playback(void); | 46 | static void init_playback(void); |
47 | static void start_prerecording(void); | ||
47 | static void start_recording(void); | 48 | static void start_recording(void); |
48 | static void stop_recording(void); | 49 | static void stop_recording(void); |
49 | static int get_unsaved_space(void); | 50 | static int get_unsaved_space(void); |
@@ -497,6 +498,17 @@ static char recording_filename[MAX_PATH]; | |||
497 | static int rec_frequency_index; /* For create_xing_header() calls */ | 498 | static int rec_frequency_index; /* For create_xing_header() calls */ |
498 | static int rec_version_index; /* For create_xing_header() calls */ | 499 | static int rec_version_index; /* For create_xing_header() calls */ |
499 | static bool disable_xing_header; /* When splitting files */ | 500 | static bool disable_xing_header; /* When splitting files */ |
501 | |||
502 | static bool prerecording; /* True if prerecording is enabled */ | ||
503 | static bool is_prerecording; /* True if we are prerecording */ | ||
504 | static int prerecord_buffer[MPEG_MAX_PRERECORD_SECONDS]; /* Array of buffer | ||
505 | indexes for each | ||
506 | prerecorded | ||
507 | second */ | ||
508 | static int prerecord_index; /* Current index in the prerecord buffer */ | ||
509 | static int prerecording_max_seconds; /* Max number of seconds to store */ | ||
510 | static int prerecord_count; /* Number of seconds in the prerecord buffer */ | ||
511 | static int prerecord_timeout; /* The tick count of the next prerecord data store */ | ||
500 | #endif | 512 | #endif |
501 | 513 | ||
502 | static int mpeg_file; | 514 | static int mpeg_file; |
@@ -865,17 +877,38 @@ static void dma_tick(void) | |||
865 | 877 | ||
866 | num_rec_bytes += i; | 878 | num_rec_bytes += i; |
867 | 879 | ||
868 | /* Signal to save the data if we are running out of buffer | 880 | if(is_prerecording) |
869 | space */ | 881 | { |
870 | num_bytes = mp3buf_write - mp3buf_read; | 882 | if(TIME_AFTER(current_tick, prerecord_timeout)) |
871 | if(num_bytes < 0) | 883 | { |
872 | num_bytes += mp3buflen; | 884 | prerecord_timeout = current_tick + HZ; |
885 | |||
886 | /* Store the write pointer every second */ | ||
887 | prerecord_buffer[prerecord_index++] = mp3buf_write; | ||
888 | |||
889 | /* Wrap if necessary */ | ||
890 | if(prerecord_index == prerecording_max_seconds) | ||
891 | prerecord_index = 0; | ||
873 | 892 | ||
874 | if(mp3buflen - num_bytes < MPEG_RECORDING_LOW_WATER && !saving) | 893 | /* Update the number of seconds recorded */ |
894 | if(prerecord_count < prerecording_max_seconds) | ||
895 | prerecord_count++; | ||
896 | } | ||
897 | } | ||
898 | else | ||
875 | { | 899 | { |
876 | saving = true; | 900 | /* Signal to save the data if we are running out of buffer |
877 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | 901 | space */ |
878 | wake_up_thread(); | 902 | num_bytes = mp3buf_write - mp3buf_read; |
903 | if(num_bytes < 0) | ||
904 | num_bytes += mp3buflen; | ||
905 | |||
906 | if(mp3buflen - num_bytes < MPEG_RECORDING_LOW_WATER && !saving) | ||
907 | { | ||
908 | saving = true; | ||
909 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | ||
910 | wake_up_thread(); | ||
911 | } | ||
879 | } | 912 | } |
880 | } | 913 | } |
881 | } | 914 | } |
@@ -1887,20 +1920,84 @@ static void mpeg_thread(void) | |||
1887 | switch(ev.id) | 1920 | switch(ev.id) |
1888 | { | 1921 | { |
1889 | case MPEG_RECORD: | 1922 | case MPEG_RECORD: |
1890 | DEBUGF("Recording...\n"); | 1923 | if(is_prerecording) |
1891 | reset_mp3_buffer(); | 1924 | { |
1925 | int startpos, i; | ||
1926 | |||
1927 | /* Go back prerecord_count seconds in the buffer */ | ||
1928 | startpos = prerecord_index - prerecord_count; | ||
1929 | if(startpos < 0) | ||
1930 | startpos += prerecording_max_seconds; | ||
1931 | |||
1932 | /* Read the mp3 buffer pointer from the prerecord buffer */ | ||
1933 | startpos = prerecord_buffer[startpos]; | ||
1934 | |||
1935 | DEBUGF("Start looking at address %x (%x)\n", | ||
1936 | mp3buf+startpos, startpos); | ||
1937 | |||
1938 | saved_header = get_last_recorded_header(); | ||
1939 | |||
1940 | mem_find_next_frame(startpos, &offset, 5000, | ||
1941 | saved_header); | ||
1942 | |||
1943 | mp3buf_read = startpos + offset; | ||
1944 | |||
1945 | DEBUGF("New mp3buf_read address: %x (%x)\n", | ||
1946 | mp3buf+mp3buf_read, mp3buf_read); | ||
1892 | 1947 | ||
1893 | /* Advance the write pointer to make | 1948 | /* Make room for headers */ |
1894 | room for an ID3 tag plus a VBR header */ | 1949 | mp3buf_read -= MPEG_RESERVED_HEADER_SPACE; |
1895 | mp3buf_write = MPEG_RESERVED_HEADER_SPACE; | 1950 | if(mp3buf_read < 0) |
1896 | memset(mp3buf, 0, MPEG_RESERVED_HEADER_SPACE); | 1951 | { |
1952 | /* Clear the bottom half */ | ||
1953 | memset(mp3buf, 0, | ||
1954 | mp3buf_read + MPEG_RESERVED_HEADER_SPACE); | ||
1897 | 1955 | ||
1898 | /* Insert the ID3 header */ | 1956 | /* And the top half */ |
1899 | memcpy(mp3buf, empty_id3_header, sizeof(empty_id3_header)); | 1957 | mp3buf_read += mp3buflen; |
1958 | memset(mp3buf + mp3buf_read, 0, | ||
1959 | mp3buflen - mp3buf_read); | ||
1960 | } | ||
1961 | else | ||
1962 | { | ||
1963 | memset(mp3buf + mp3buf_read, 0, | ||
1964 | MPEG_RESERVED_HEADER_SPACE); | ||
1965 | } | ||
1966 | |||
1967 | /* Copy the empty ID3 header */ | ||
1968 | startpos = mp3buf_read; | ||
1969 | for(i = 0;i < (int)sizeof(empty_id3_header);i++) | ||
1970 | { | ||
1971 | mp3buf[startpos++] = empty_id3_header[i]; | ||
1972 | if(startpos == mp3buflen) | ||
1973 | startpos = 0; | ||
1974 | } | ||
1975 | |||
1976 | DEBUGF("New mp3buf_read address (reservation): %x\n", | ||
1977 | mp3buf+mp3buf_read); | ||
1978 | |||
1979 | DEBUGF("Prerecording...\n"); | ||
1980 | } | ||
1981 | else | ||
1982 | { | ||
1983 | reset_mp3_buffer(); | ||
1984 | |||
1985 | num_rec_bytes = 0; | ||
1986 | |||
1987 | /* Advance the write pointer to make | ||
1988 | room for an ID3 tag plus a VBR header */ | ||
1989 | mp3buf_write = MPEG_RESERVED_HEADER_SPACE; | ||
1990 | memset(mp3buf, 0, MPEG_RESERVED_HEADER_SPACE); | ||
1991 | |||
1992 | /* Insert the ID3 header */ | ||
1993 | memcpy(mp3buf, empty_id3_header, | ||
1994 | sizeof(empty_id3_header)); | ||
1995 | |||
1996 | DEBUGF("Recording...\n"); | ||
1997 | } | ||
1900 | 1998 | ||
1901 | start_recording(); | 1999 | start_recording(); |
1902 | demand_irq_enable(true); | 2000 | |
1903 | |||
1904 | mpeg_file = open(recording_filename, O_WRONLY|O_CREAT); | 2001 | mpeg_file = open(recording_filename, O_WRONLY|O_CREAT); |
1905 | 2002 | ||
1906 | if(mpeg_file < 0) | 2003 | if(mpeg_file < 0) |
@@ -1910,14 +2007,13 @@ static void mpeg_thread(void) | |||
1910 | 2007 | ||
1911 | case MPEG_STOP: | 2008 | case MPEG_STOP: |
1912 | DEBUGF("MPEG_STOP\n"); | 2009 | DEBUGF("MPEG_STOP\n"); |
1913 | demand_irq_enable(false); | ||
1914 | 2010 | ||
1915 | /* Store the last recorded header for later use by the | 2011 | /* Store the last recorded header for later use by the |
1916 | Xing header generation */ | 2012 | Xing header generation */ |
1917 | saved_header = get_last_recorded_header(); | 2013 | saved_header = get_last_recorded_header(); |
1918 | 2014 | ||
1919 | stop_recording(); | 2015 | stop_recording(); |
1920 | 2016 | ||
1921 | /* Save the remaining data in the buffer */ | 2017 | /* Save the remaining data in the buffer */ |
1922 | stop_pending = true; | 2018 | stop_pending = true; |
1923 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | 2019 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); |
@@ -1942,6 +2038,11 @@ static void mpeg_thread(void) | |||
1942 | if(num_recorded_frames == 0x7ffff) | 2038 | if(num_recorded_frames == 0x7ffff) |
1943 | num_recorded_frames = 0; | 2039 | num_recorded_frames = 0; |
1944 | 2040 | ||
2041 | /* Also, if we have been prerecording, the frame count | ||
2042 | will be wrong */ | ||
2043 | if(prerecording) | ||
2044 | num_recorded_frames = 0; | ||
2045 | |||
1945 | /* saved_header is saved right before stopping | 2046 | /* saved_header is saved right before stopping |
1946 | the MAS */ | 2047 | the MAS */ |
1947 | framelen = create_xing_header(mpeg_file, 0, | 2048 | framelen = create_xing_header(mpeg_file, 0, |
@@ -1970,6 +2071,11 @@ static void mpeg_thread(void) | |||
1970 | } | 2071 | } |
1971 | } | 2072 | } |
1972 | #endif | 2073 | #endif |
2074 | |||
2075 | if(prerecording) | ||
2076 | { | ||
2077 | start_prerecording(); | ||
2078 | } | ||
1973 | mpeg_stop_done = true; | 2079 | mpeg_stop_done = true; |
1974 | break; | 2080 | break; |
1975 | 2081 | ||
@@ -2117,7 +2223,6 @@ static void mpeg_thread(void) | |||
2117 | if(errno == ENOSPC) | 2223 | if(errno == ENOSPC) |
2118 | { | 2224 | { |
2119 | mpeg_errno = MPEGERR_DISK_FULL; | 2225 | mpeg_errno = MPEGERR_DISK_FULL; |
2120 | demand_irq_enable(false); | ||
2121 | stop_recording(); | 2226 | stop_recording(); |
2122 | queue_post(&mpeg_queue, MPEG_STOP_DONE, 0); | 2227 | queue_post(&mpeg_queue, MPEG_STOP_DONE, 0); |
2123 | break; | 2228 | break; |
@@ -2161,18 +2266,22 @@ static void mpeg_thread(void) | |||
2161 | break; | 2266 | break; |
2162 | 2267 | ||
2163 | case SYS_USB_CONNECTED: | 2268 | case SYS_USB_CONNECTED: |
2164 | is_playing = false; | 2269 | /* We can safely go to USB mode if no recording |
2165 | paused = false; | 2270 | is taking place */ |
2166 | stop_playing(); | 2271 | if((!is_recording || is_prerecording) && mpeg_stop_done) |
2167 | #ifndef SIMULATOR | 2272 | { |
2273 | /* Even if we aren't recording, we still call this | ||
2274 | function, to put the MAS in monitoring mode, | ||
2275 | to save power. */ | ||
2276 | stop_recording(); | ||
2168 | 2277 | ||
2169 | /* Tell the USB thread that we are safe */ | 2278 | /* Tell the USB thread that we are safe */ |
2170 | DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n"); | 2279 | DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n"); |
2171 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | 2280 | usb_acknowledge(SYS_USB_CONNECTED_ACK); |
2172 | 2281 | ||
2173 | /* Wait until the USB cable is extracted again */ | 2282 | /* Wait until the USB cable is extracted again */ |
2174 | usb_wait_for_disconnect(&mpeg_queue); | 2283 | usb_wait_for_disconnect(&mpeg_queue); |
2175 | #endif | 2284 | } |
2176 | break; | 2285 | break; |
2177 | } | 2286 | } |
2178 | } | 2287 | } |
@@ -2245,22 +2354,90 @@ bool mpeg_has_changed_track(void) | |||
2245 | } | 2354 | } |
2246 | 2355 | ||
2247 | #ifdef HAVE_MAS3587F | 2356 | #ifdef HAVE_MAS3587F |
2248 | void mpeg_init_recording(void) | 2357 | void mpeg_init_playback(void) |
2249 | { | 2358 | { |
2250 | init_recording_done = false; | 2359 | init_playback_done = false; |
2251 | queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL); | 2360 | queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, NULL); |
2252 | 2361 | ||
2253 | while(!init_recording_done) | 2362 | while(!init_playback_done) |
2254 | sleep_thread(); | 2363 | sleep_thread(); |
2255 | wake_up_thread(); | 2364 | wake_up_thread(); |
2256 | } | 2365 | } |
2257 | 2366 | ||
2258 | void mpeg_init_playback(void) | 2367 | static void init_playback(void) |
2259 | { | 2368 | { |
2260 | init_playback_done = false; | 2369 | unsigned long val; |
2261 | queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, NULL); | 2370 | int rc; |
2262 | 2371 | ||
2263 | while(!init_playback_done) | 2372 | if(mpeg_mode == MPEG_ENCODER) |
2373 | stop_recording(); | ||
2374 | |||
2375 | stop_dma(); | ||
2376 | |||
2377 | mas_reset(); | ||
2378 | |||
2379 | /* Enable the audio CODEC and the DSP core, max analog voltage range */ | ||
2380 | rc = mas_direct_config_write(MAS_CONTROL, 0x8c00); | ||
2381 | if(rc < 0) | ||
2382 | panicf("mas_ctrl_w: %d", rc); | ||
2383 | |||
2384 | /* Stop the current application */ | ||
2385 | val = 0; | ||
2386 | mas_writemem(MAS_BANK_D0,0x7f6,&val,1); | ||
2387 | do | ||
2388 | { | ||
2389 | mas_readmem(MAS_BANK_D0, 0x7f7, &val, 1); | ||
2390 | } while(val); | ||
2391 | |||
2392 | /* Enable the D/A Converter */ | ||
2393 | mas_codec_writereg(0x0, 0x0001); | ||
2394 | |||
2395 | /* ADC scale 0%, DSP scale 100% */ | ||
2396 | mas_codec_writereg(6, 0x0000); | ||
2397 | mas_codec_writereg(7, 0x4000); | ||
2398 | |||
2399 | /* Disable SDO and SDI */ | ||
2400 | val = 0x0d; | ||
2401 | mas_writemem(MAS_BANK_D0,0x7f2,&val,1); | ||
2402 | |||
2403 | /* Set Demand mode and validate all settings */ | ||
2404 | val = 0x25; | ||
2405 | mas_writemem(MAS_BANK_D0,0x7f1,&val,1); | ||
2406 | |||
2407 | /* Start the Layer2/3 decoder applications */ | ||
2408 | val = 0x0c; | ||
2409 | mas_writemem(MAS_BANK_D0,0x7f6,&val,1); | ||
2410 | do | ||
2411 | { | ||
2412 | mas_readmem(MAS_BANK_D0, 0x7f7, &val, 1); | ||
2413 | } while((val & 0x0c) != 0x0c); | ||
2414 | |||
2415 | mpeg_sound_channel_config(MPEG_SOUND_STEREO); | ||
2416 | |||
2417 | mpeg_mode = MPEG_DECODER; | ||
2418 | |||
2419 | /* set IRQ6 to edge detect */ | ||
2420 | ICR |= 0x02; | ||
2421 | |||
2422 | /* set IRQ6 prio 8 */ | ||
2423 | IPRB = ( IPRB & 0xff0f ) | 0x0080; | ||
2424 | |||
2425 | DEBUGF("MAS Decoding application started\n"); | ||
2426 | } | ||
2427 | |||
2428 | /**************************************************************************** | ||
2429 | ** | ||
2430 | ** | ||
2431 | ** Recording functions | ||
2432 | ** | ||
2433 | ** | ||
2434 | ***************************************************************************/ | ||
2435 | void mpeg_init_recording(void) | ||
2436 | { | ||
2437 | init_recording_done = false; | ||
2438 | queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL); | ||
2439 | |||
2440 | while(!init_recording_done) | ||
2264 | sleep_thread(); | 2441 | sleep_thread(); |
2265 | wake_up_thread(); | 2442 | wake_up_thread(); |
2266 | } | 2443 | } |
@@ -2270,6 +2447,9 @@ static void init_recording(void) | |||
2270 | unsigned long val; | 2447 | unsigned long val; |
2271 | int rc; | 2448 | int rc; |
2272 | 2449 | ||
2450 | /* Disable IRQ6 */ | ||
2451 | IPRB &= 0xff0f; | ||
2452 | |||
2273 | stop_playing(); | 2453 | stop_playing(); |
2274 | is_playing = false; | 2454 | is_playing = false; |
2275 | paused = false; | 2455 | paused = false; |
@@ -2283,6 +2463,9 @@ static void init_recording(void) | |||
2283 | 2463 | ||
2284 | /* Init the recording variables */ | 2464 | /* Init the recording variables */ |
2285 | is_recording = false; | 2465 | is_recording = false; |
2466 | is_prerecording = false; | ||
2467 | |||
2468 | mpeg_stop_done = true; | ||
2286 | 2469 | ||
2287 | mas_reset(); | 2470 | mas_reset(); |
2288 | 2471 | ||
@@ -2324,7 +2507,7 @@ static void init_recording(void) | |||
2324 | 2507 | ||
2325 | /* No mute */ | 2508 | /* No mute */ |
2326 | val = 0; | 2509 | val = 0; |
2327 | mas_writemem(MAS_BANK_D0, 0x7f9, &val, 1); | 2510 | mas_writemem(MAS_BANK_D0, 0x7f9, &val, 1); |
2328 | 2511 | ||
2329 | /* Set Demand mode, no monitoring and validate all settings */ | 2512 | /* Set Demand mode, no monitoring and validate all settings */ |
2330 | val = 0x125; | 2513 | val = 0x125; |
@@ -2345,70 +2528,16 @@ static void init_recording(void) | |||
2345 | Now let's wait for some data to be encoded. */ | 2528 | Now let's wait for some data to be encoded. */ |
2346 | sleep(20); | 2529 | sleep(20); |
2347 | 2530 | ||
2348 | /* Disable IRQ6 */ | 2531 | /* Now set it to Monitoring mode as default, saves power */ |
2349 | IPRB &= 0xff0f; | 2532 | val = 0x525; |
2533 | mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1); | ||
2350 | 2534 | ||
2351 | mpeg_mode = MPEG_ENCODER; | 2535 | mpeg_mode = MPEG_ENCODER; |
2352 | 2536 | ||
2353 | DEBUGF("MAS Recording application started\n"); | 2537 | DEBUGF("MAS Recording application started\n"); |
2354 | } | ||
2355 | |||
2356 | static void init_playback(void) | ||
2357 | { | ||
2358 | unsigned long val; | ||
2359 | int rc; | ||
2360 | |||
2361 | stop_dma(); | ||
2362 | |||
2363 | mas_reset(); | ||
2364 | |||
2365 | /* Enable the audio CODEC and the DSP core, max analog voltage range */ | ||
2366 | rc = mas_direct_config_write(MAS_CONTROL, 0x8c00); | ||
2367 | if(rc < 0) | ||
2368 | panicf("mas_ctrl_w: %d", rc); | ||
2369 | |||
2370 | /* Stop the current application */ | ||
2371 | val = 0; | ||
2372 | mas_writemem(MAS_BANK_D0,0x7f6,&val,1); | ||
2373 | do | ||
2374 | { | ||
2375 | mas_readmem(MAS_BANK_D0, 0x7f7, &val, 1); | ||
2376 | } while(val); | ||
2377 | |||
2378 | /* Enable the D/A Converter */ | ||
2379 | mas_codec_writereg(0x0, 0x0001); | ||
2380 | |||
2381 | /* ADC scale 0%, DSP scale 100% */ | ||
2382 | mas_codec_writereg(6, 0x0000); | ||
2383 | mas_codec_writereg(7, 0x4000); | ||
2384 | |||
2385 | /* Disable SDO and SDI */ | ||
2386 | val = 0x0d; | ||
2387 | mas_writemem(MAS_BANK_D0,0x7f2,&val,1); | ||
2388 | |||
2389 | /* Set Demand mode and validate all settings */ | ||
2390 | val = 0x25; | ||
2391 | mas_writemem(MAS_BANK_D0,0x7f1,&val,1); | ||
2392 | |||
2393 | /* Start the Layer2/3 decoder applications */ | ||
2394 | val = 0x0c; | ||
2395 | mas_writemem(MAS_BANK_D0,0x7f6,&val,1); | ||
2396 | do | ||
2397 | { | ||
2398 | mas_readmem(MAS_BANK_D0, 0x7f7, &val, 1); | ||
2399 | } while((val & 0x0c) != 0x0c); | ||
2400 | |||
2401 | mpeg_sound_channel_config(MPEG_SOUND_STEREO); | ||
2402 | |||
2403 | mpeg_mode = MPEG_DECODER; | ||
2404 | |||
2405 | /* set IRQ6 to edge detect */ | ||
2406 | ICR |= 0x02; | ||
2407 | |||
2408 | /* set IRQ6 prio 8 */ | ||
2409 | IPRB = ( IPRB & 0xff0f ) | 0x0080; | ||
2410 | 2538 | ||
2411 | DEBUGF("MAS Decoding application started\n"); | 2539 | /* At this point, all settings are the reset MAS defaults, next thing is to |
2540 | call mpeg_set_recording_options(). */ | ||
2412 | } | 2541 | } |
2413 | 2542 | ||
2414 | void mpeg_record(char *filename) | 2543 | void mpeg_record(char *filename) |
@@ -2418,53 +2547,109 @@ void mpeg_record(char *filename) | |||
2418 | strncpy(recording_filename, filename, MAX_PATH - 1); | 2547 | strncpy(recording_filename, filename, MAX_PATH - 1); |
2419 | recording_filename[MAX_PATH - 1] = 0; | 2548 | recording_filename[MAX_PATH - 1] = 0; |
2420 | 2549 | ||
2421 | num_rec_bytes = 0; | ||
2422 | disable_xing_header = false; | 2550 | disable_xing_header = false; |
2423 | queue_post(&mpeg_queue, MPEG_RECORD, NULL); | 2551 | queue_post(&mpeg_queue, MPEG_RECORD, NULL); |
2424 | } | 2552 | } |
2425 | 2553 | ||
2426 | static void start_recording(void) | 2554 | static void start_prerecording(void) |
2427 | { | 2555 | { |
2428 | unsigned long val; | 2556 | unsigned long val; |
2429 | 2557 | ||
2430 | num_recorded_frames = 0; | 2558 | DEBUGF("Starting prerecording\n"); |
2431 | 2559 | ||
2432 | /* Stop monitoring and record for real */ | 2560 | prerecord_index = 0; |
2561 | prerecord_count = 0; | ||
2562 | prerecord_timeout = current_tick + HZ; | ||
2563 | memset(prerecord_buffer, 0, sizeof(prerecord_buffer)); | ||
2564 | reset_mp3_buffer(); | ||
2565 | |||
2566 | is_prerecording = true; | ||
2567 | |||
2568 | /* Stop monitoring and start the encoder */ | ||
2433 | mas_readmem(MAS_BANK_D0, 0x7f1, &val, 1); | 2569 | mas_readmem(MAS_BANK_D0, 0x7f1, &val, 1); |
2434 | val &= ~(1 << 10); | 2570 | val &= ~(1 << 10); |
2435 | val |= 1; | 2571 | val |= 1; |
2436 | mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1); | 2572 | mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1); |
2573 | DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f1, %x)\n", val); | ||
2437 | 2574 | ||
2438 | /* Wait until the DSP has accepted the settings */ | 2575 | /* Wait until the DSP has accepted the settings */ |
2439 | do | 2576 | do |
2440 | { | 2577 | { |
2441 | mas_readmem(MAS_BANK_D0, 0x7f1, &val,1); | 2578 | mas_readmem(MAS_BANK_D0, 0x7f1, &val,1); |
2442 | } while(val & 1); | 2579 | } while(val & 1); |
2443 | |||
2444 | sleep(20); | ||
2445 | 2580 | ||
2446 | /* Store the current time */ | 2581 | sleep(20); |
2447 | record_start_time = current_tick; | ||
2448 | 2582 | ||
2449 | is_recording = true; | 2583 | is_recording = true; |
2450 | stop_pending = false; | 2584 | stop_pending = false; |
2451 | saving = false; | 2585 | saving = false; |
2586 | |||
2587 | demand_irq_enable(true); | ||
2588 | } | ||
2589 | |||
2590 | static void start_recording(void) | ||
2591 | { | ||
2592 | unsigned long val; | ||
2593 | |||
2594 | num_recorded_frames = 0; | ||
2595 | |||
2596 | if(is_prerecording) | ||
2597 | { | ||
2598 | /* This will make the IRQ handler start recording | ||
2599 | for real, i.e send MPEG_SAVE_DATA messages when | ||
2600 | the buffer is full */ | ||
2601 | is_prerecording = false; | ||
2602 | } | ||
2603 | else | ||
2604 | { | ||
2605 | /* If prerecording is off, we need to stop the monitoring | ||
2606 | and start the encoder */ | ||
2607 | mas_readmem(MAS_BANK_D0, 0x7f1, &val, 1); | ||
2608 | val &= ~(1 << 10); | ||
2609 | val |= 1; | ||
2610 | mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1); | ||
2611 | DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f1, %x)\n", val); | ||
2612 | |||
2613 | /* Wait until the DSP has accepted the settings */ | ||
2614 | do | ||
2615 | { | ||
2616 | mas_readmem(MAS_BANK_D0, 0x7f1, &val,1); | ||
2617 | } while(val & 1); | ||
2618 | |||
2619 | sleep(20); | ||
2620 | } | ||
2621 | |||
2622 | is_recording = true; | ||
2623 | stop_pending = false; | ||
2624 | saving = false; | ||
2625 | |||
2626 | /* Store the current time */ | ||
2627 | if(prerecording) | ||
2628 | record_start_time = current_tick - prerecord_count * HZ; | ||
2629 | else | ||
2630 | record_start_time = current_tick; | ||
2631 | |||
2632 | demand_irq_enable(true); | ||
2452 | } | 2633 | } |
2453 | 2634 | ||
2454 | static void stop_recording(void) | 2635 | static void stop_recording(void) |
2455 | { | 2636 | { |
2456 | unsigned long val; | 2637 | unsigned long val; |
2457 | 2638 | ||
2458 | is_recording = false; | 2639 | demand_irq_enable(false); |
2459 | 2640 | ||
2641 | is_recording = false; | ||
2642 | is_prerecording = false; | ||
2643 | |||
2460 | /* Read the number of frames recorded */ | 2644 | /* Read the number of frames recorded */ |
2461 | mas_readmem(MAS_BANK_D0, 0xfd0, &num_recorded_frames, 1); | 2645 | mas_readmem(MAS_BANK_D0, 0xfd0, &num_recorded_frames, 1); |
2462 | 2646 | ||
2463 | /* Start monitoring */ | 2647 | /* Start monitoring */ |
2464 | mas_readmem(MAS_BANK_D0, 0x7f1, &val, 1); | 2648 | mas_readmem(MAS_BANK_D0, 0x7f1, &val, 1); |
2465 | val |= (1 << 10) | 1; | 2649 | val |= (1 << 10) | 1; |
2466 | mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1); | 2650 | mas_writemem(MAS_BANK_D0, 0x7f1, &val, 1); |
2467 | 2651 | DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f1, %x)\n", val); | |
2652 | |||
2468 | /* Wait until the DSP has accepted the settings */ | 2653 | /* Wait until the DSP has accepted the settings */ |
2469 | do | 2654 | do |
2470 | { | 2655 | { |
@@ -2474,6 +2659,82 @@ static void stop_recording(void) | |||
2474 | drain_dma_buffer(); | 2659 | drain_dma_buffer(); |
2475 | } | 2660 | } |
2476 | 2661 | ||
2662 | void mpeg_set_recording_options(int frequency, int quality, | ||
2663 | int source, int channel_mode, | ||
2664 | bool editable, int prerecord_time) | ||
2665 | { | ||
2666 | bool is_mpeg1; | ||
2667 | unsigned long val; | ||
2668 | |||
2669 | is_mpeg1 = (frequency < 3)?true:false; | ||
2670 | |||
2671 | rec_version_index = is_mpeg1?3:2; | ||
2672 | rec_frequency_index = frequency % 3; | ||
2673 | |||
2674 | val = (quality << 17) | | ||
2675 | (rec_frequency_index << 10) | | ||
2676 | ((is_mpeg1?1:0) << 9) | | ||
2677 | (1 << 8) | /* CRC on */ | ||
2678 | (((channel_mode * 2 + 1) & 3) << 6) | | ||
2679 | (1 << 5) /* MS-stereo */ | | ||
2680 | (1 << 2) /* Is an original */; | ||
2681 | mas_writemem(MAS_BANK_D0, 0x7f0, &val,1); | ||
2682 | |||
2683 | DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f0, %x)\n", val); | ||
2684 | |||
2685 | val = editable?4:0; | ||
2686 | mas_writemem(MAS_BANK_D0, 0x7f9, &val,1); | ||
2687 | |||
2688 | DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f9, %x)\n", val); | ||
2689 | |||
2690 | val = (((source < 2)?1:2) << 8) | /* Input select */ | ||
2691 | (1 << 5) | /* SDO strobe invert */ | ||
2692 | ((is_mpeg1?0:1) << 3) | | ||
2693 | (1 << 2) | /* Inverted SIBC clock signal */ | ||
2694 | 1; /* Validate */ | ||
2695 | mas_writemem(MAS_BANK_D0, 0x7f1, &val,1); | ||
2696 | |||
2697 | DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f1, %x)\n", val); | ||
2698 | |||
2699 | drain_dma_buffer(); | ||
2700 | |||
2701 | if(source == 0) /* Mic */ | ||
2702 | { | ||
2703 | /* Copy left channel to right (mono mode) */ | ||
2704 | mas_codec_writereg(8, 0x8000); | ||
2705 | } | ||
2706 | else | ||
2707 | { | ||
2708 | /* Stereo input mode */ | ||
2709 | mas_codec_writereg(8, 0); | ||
2710 | } | ||
2711 | |||
2712 | prerecording_max_seconds = prerecord_time; | ||
2713 | if(prerecording_max_seconds) | ||
2714 | { | ||
2715 | prerecording = true; | ||
2716 | start_prerecording(); | ||
2717 | } | ||
2718 | else | ||
2719 | { | ||
2720 | prerecording = false; | ||
2721 | is_prerecording = false; | ||
2722 | is_recording = false; | ||
2723 | } | ||
2724 | } | ||
2725 | |||
2726 | /* If use_mic is true, the left gain is used */ | ||
2727 | void mpeg_set_recording_gain(int left, int right, bool use_mic) | ||
2728 | { | ||
2729 | /* Enable both left and right A/D */ | ||
2730 | mas_codec_writereg(0x0, | ||
2731 | (left << 12) | | ||
2732 | (right << 8) | | ||
2733 | (left << 4) | | ||
2734 | (use_mic?0x0008:0) | /* Connect left A/D to mic */ | ||
2735 | 0x0007); | ||
2736 | } | ||
2737 | |||
2477 | void mpeg_new_file(char *filename) | 2738 | void mpeg_new_file(char *filename) |
2478 | { | 2739 | { |
2479 | mpeg_errno = 0; | 2740 | mpeg_errno = 0; |
@@ -2492,16 +2753,37 @@ void mpeg_new_file(char *filename) | |||
2492 | 2753 | ||
2493 | unsigned long mpeg_recorded_time(void) | 2754 | unsigned long mpeg_recorded_time(void) |
2494 | { | 2755 | { |
2756 | if(is_prerecording) | ||
2757 | return prerecord_count * HZ; | ||
2758 | |||
2495 | if(is_recording) | 2759 | if(is_recording) |
2496 | return current_tick - record_start_time; | 2760 | return current_tick - record_start_time; |
2497 | else | 2761 | |
2498 | return 0; | 2762 | return 0; |
2499 | } | 2763 | } |
2500 | 2764 | ||
2501 | unsigned long mpeg_num_recorded_bytes(void) | 2765 | unsigned long mpeg_num_recorded_bytes(void) |
2502 | { | 2766 | { |
2767 | int num_bytes; | ||
2768 | int index; | ||
2769 | |||
2503 | if(is_recording) | 2770 | if(is_recording) |
2504 | return num_rec_bytes; | 2771 | { |
2772 | if(is_prerecording) | ||
2773 | { | ||
2774 | index = prerecord_index - prerecord_count; | ||
2775 | if(index < 0) | ||
2776 | index += prerecording_max_seconds; | ||
2777 | |||
2778 | num_bytes = mp3buf_write - prerecord_buffer[index]; | ||
2779 | if(num_bytes < 0) | ||
2780 | num_bytes += mp3buflen; | ||
2781 | |||
2782 | return num_bytes;; | ||
2783 | } | ||
2784 | else | ||
2785 | return num_rec_bytes; | ||
2786 | } | ||
2505 | else | 2787 | else |
2506 | return 0; | 2788 | return 0; |
2507 | } | 2789 | } |
@@ -2660,8 +2942,11 @@ int mpeg_status(void) | |||
2660 | ret |= MPEG_STATUS_PAUSE; | 2942 | ret |= MPEG_STATUS_PAUSE; |
2661 | 2943 | ||
2662 | #ifdef HAVE_MAS3587F | 2944 | #ifdef HAVE_MAS3587F |
2663 | if(is_recording) | 2945 | if(is_recording && !is_prerecording) |
2664 | ret |= MPEG_STATUS_RECORD; | 2946 | ret |= MPEG_STATUS_RECORD; |
2947 | |||
2948 | if(is_prerecording) | ||
2949 | ret |= MPEG_STATUS_PRERECORD; | ||
2665 | #endif | 2950 | #endif |
2666 | 2951 | ||
2667 | if(mpeg_errno) | 2952 | if(mpeg_errno) |
@@ -3057,73 +3342,6 @@ void mpeg_set_pitch(int pitch) | |||
3057 | } | 3342 | } |
3058 | #endif | 3343 | #endif |
3059 | 3344 | ||
3060 | #ifdef HAVE_MAS3587F | ||
3061 | void mpeg_set_recording_options(int frequency, int quality, | ||
3062 | int source, int channel_mode, | ||
3063 | bool editable) | ||
3064 | { | ||
3065 | bool is_mpeg1; | ||
3066 | unsigned long val; | ||
3067 | |||
3068 | is_mpeg1 = (frequency < 3)?true:false; | ||
3069 | |||
3070 | rec_version_index = is_mpeg1?3:2; | ||
3071 | rec_frequency_index = frequency % 3; | ||
3072 | |||
3073 | val = (quality << 17) | | ||
3074 | (rec_frequency_index << 10) | | ||
3075 | ((is_mpeg1?1:0) << 9) | | ||
3076 | (1 << 8) | /* CRC on */ | ||
3077 | (((channel_mode * 2 + 1) & 3) << 6) | | ||
3078 | (1 << 5) /* MS-stereo */ | | ||
3079 | (1 << 2) /* Is an original */; | ||
3080 | mas_writemem(MAS_BANK_D0, 0x7f0, &val,1); | ||
3081 | |||
3082 | DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f0, %x)\n", val); | ||
3083 | |||
3084 | val = editable?4:0; | ||
3085 | mas_writemem(MAS_BANK_D0, 0x7f9, &val,1); | ||
3086 | |||
3087 | DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f9, %x)\n", val); | ||
3088 | |||
3089 | val = ((!is_recording << 10) | /* Monitoring */ | ||
3090 | ((source < 2)?1:2) << 8) | /* Input select */ | ||
3091 | (1 << 5) | /* SDO strobe invert */ | ||
3092 | ((is_mpeg1?0:1) << 3) | | ||
3093 | (1 << 2) | /* Inverted SIBC clock signal */ | ||
3094 | 1; /* Validate */ | ||
3095 | mas_writemem(MAS_BANK_D0, 0x7f1, &val,1); | ||
3096 | |||
3097 | DEBUGF("mas_writemem(MAS_BANK_D0, 0x7f1, %x)\n", val); | ||
3098 | |||
3099 | drain_dma_buffer(); | ||
3100 | |||
3101 | if(source == 0) /* Mic */ | ||
3102 | { | ||
3103 | /* Copy left channel to right (mono mode) */ | ||
3104 | mas_codec_writereg(8, 0x8000); | ||
3105 | } | ||
3106 | else | ||
3107 | { | ||
3108 | /* Stereo input mode */ | ||
3109 | mas_codec_writereg(8, 0); | ||
3110 | } | ||
3111 | } | ||
3112 | |||
3113 | /* If use_mic is true, the left gain is used */ | ||
3114 | void mpeg_set_recording_gain(int left, int right, bool use_mic) | ||
3115 | { | ||
3116 | /* Enable both left and right A/D */ | ||
3117 | mas_codec_writereg(0x0, | ||
3118 | (left << 12) | | ||
3119 | (right << 8) | | ||
3120 | (left << 4) | | ||
3121 | (use_mic?0x0008:0) | /* Connect left A/D to mic */ | ||
3122 | 0x0007); | ||
3123 | } | ||
3124 | |||
3125 | #endif | ||
3126 | |||
3127 | #ifdef SIMULATOR | 3345 | #ifdef SIMULATOR |
3128 | static char mpeg_stack[DEFAULT_STACK_SIZE]; | 3346 | static char mpeg_stack[DEFAULT_STACK_SIZE]; |
3129 | static char mpeg_thread_name[] = "mpeg"; | 3347 | static char mpeg_thread_name[] = "mpeg"; |