📄 mpeg.c
字号:
space += mp3buflen; return space;}static int get_unplayed_space_current_song(void){ int space; if (num_tracks_in_memory() > 1) { int track_offset = (tag_read_idx+1) & MAX_ID3_TAGS_MASK; space = id3tags[track_offset]->mempos - mp3buf_read; } else { space = mp3buf_write - mp3buf_read; } if (space < 0) space += mp3buflen; return space;}static int get_unswapped_space(void){ int space = mp3buf_write - mp3buf_swapwrite; if (space < 0) space += mp3buflen; return space;}#ifdef HAVE_MAS3587Fstatic int get_unsaved_space(void){ int space = mp3buf_write - mp3buf_read; if (space < 0) space += mp3buflen; return space;}#endif /* #ifdef HAVE_MAS3587F */#ifdef HAVE_MAS3587F#ifdef DEBUGstatic long timing_info_index = 0;static long timing_info[1024];#endif /* #ifdef DEBUG */static bool inverted_pr;static unsigned long num_rec_bytes;static unsigned long num_recorded_frames;static void drain_dma_buffer(void){ if(inverted_pr) { while((*((volatile unsigned char *)PBDR_ADDR) & 0x40)) { or_b(0x08, &PADRH); while(*((volatile unsigned char *)PBDR_ADDR) & 0x80); /* It must take at least 5 cycles before the data is read */ asm(" nop\n nop\n nop\n"); asm(" nop\n nop\n nop\n"); and_b(~0x08, &PADRH); while(!(*((volatile unsigned char *)PBDR_ADDR) & 0x80)); } } else { while((*((volatile unsigned char *)PBDR_ADDR) & 0x40)) { and_b(~0x08, &PADRH); while(*((volatile unsigned char *)PBDR_ADDR) & 0x80); /* It must take at least 5 cycles before the data is read */ asm(" nop\n nop\n nop\n"); asm(" nop\n nop\n nop\n"); or_b(0x08, &PADRH); while(!(*((volatile unsigned char *)PBDR_ADDR) & 0x80)); } }}#endif /* #ifdef HAVE_MAS3587F */void rec_tick (void) __attribute__ ((section (".icode")));void rec_tick(void){#ifdef HAVE_MAS3587F int i; int num_bytes; if(is_recording && (PBDR & 0x4000)) {#ifdef DEBUG timing_info[timing_info_index++] = current_tick; TCNT2 = 0;#endif /* #ifdef DEBUG */ /* We read as long as EOD is high, but max 30 bytes. This code is optimized, and should probably be written in assembler instead. */ if(inverted_pr) { i = 0; while((*((volatile unsigned char *)PBDR_ADDR) & 0x40) && i < 30) { or_b(0x08, &PADRH); while(*((volatile unsigned char *)PBDR_ADDR) & 0x80); /* It must take at least 5 cycles before the data is read */ asm(" nop\n nop\n nop\n"); mp3buf[mp3buf_write++] = *(unsigned char *)0x4000000; if(mp3buf_write >= mp3buflen) mp3buf_write = 0; i++; and_b(~0x08, &PADRH); /* No wait for /RTW, cause it's not necessary */ } } else /* !inverted_pr */ { i = 0; while((*((volatile unsigned char *)PBDR_ADDR) & 0x40) && i < 30) { and_b(~0x08, &PADRH); while(*((volatile unsigned char *)PBDR_ADDR) & 0x80); /* It must take at least 5 cycles before the data is read */ asm(" nop\n nop\n nop\n"); mp3buf[mp3buf_write++] = *(unsigned char *)0x4000000; if(mp3buf_write >= mp3buflen) mp3buf_write = 0; i++; or_b(0x08, &PADRH); /* No wait for /RTW, cause it's not necessary */ } }#ifdef DEBUG timing_info[timing_info_index++] = TCNT2 + (i << 16); timing_info_index &= 0x3ff;#endif /* #ifdef DEBUG */ num_rec_bytes += i; if(is_prerecording) { if(TIME_AFTER(current_tick, prerecord_timeout)) { prerecord_timeout = current_tick + HZ; /* Store the write pointer every second */ prerecord_buffer[prerecord_index++] = mp3buf_write; /* Wrap if necessary */ if(prerecord_index == prerecording_max_seconds) prerecord_index = 0; /* Update the number of seconds recorded */ if(prerecord_count < prerecording_max_seconds) prerecord_count++; } } else { /* Signal to save the data if we are running out of buffer space */ num_bytes = mp3buf_write - mp3buf_read; if(num_bytes < 0) num_bytes += mp3buflen; if(mp3buflen - num_bytes < MPEG_RECORDING_LOW_WATER && !saving) { saving = true; queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); wake_up_thread(); } } }#endif /* #ifdef HAVE_MAS3587F */}void playback_tick(void){ id3tags[tag_read_idx]->id3.elapsed += (current_tick - last_dma_tick) * 1000 / HZ; last_dma_tick = current_tick;}static void reset_mp3_buffer(void){ mp3buf_read = 0; mp3buf_write = 0; mp3buf_swapwrite = 0; lowest_watermark_level = mp3buflen;} /* DMA transfer end interrupt callback */static void transfer_end(unsigned char** ppbuf, int* psize){ if(playing && !paused) { int unplayed_space_left; int space_until_end_of_buffer; int track_offset = (tag_read_idx+1) & MAX_ID3_TAGS_MASK; mp3buf_read += last_dma_chunk_size; if(mp3buf_read >= mp3buflen) mp3buf_read = 0; /* First, check if we are on a track boundary */ if (num_tracks_in_memory() > 0) { if (mp3buf_read == id3tags[track_offset]->mempos) { queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0); track_offset = (track_offset+1) & MAX_ID3_TAGS_MASK; } } unplayed_space_left = get_unplayed_space(); space_until_end_of_buffer = mp3buflen - mp3buf_read; if(!filling && unplayed_space_left < low_watermark) { filling = true; queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); } if(unplayed_space_left) { last_dma_chunk_size = MIN(0x2000, unplayed_space_left); last_dma_chunk_size = MIN(last_dma_chunk_size, space_until_end_of_buffer); /* several tracks loaded? */ if (num_tracks_in_memory() > 1) { /* will we move across the track boundary? */ if (( mp3buf_read < id3tags[track_offset]->mempos ) && ((mp3buf_read+last_dma_chunk_size) > id3tags[track_offset]->mempos )) { /* Make sure that we end exactly on the boundary */ last_dma_chunk_size = id3tags[track_offset]->mempos - mp3buf_read; } } *psize = last_dma_chunk_size & 0xffff; *ppbuf = mp3buf + mp3buf_read; id3tags[tag_read_idx]->id3.offset += last_dma_chunk_size; /* Update the watermark debug level */ if(unplayed_space_left < lowest_watermark_level) lowest_watermark_level = unplayed_space_left; } else { /* Check if the end of data is because of a hard disk error. If there is an open file handle, we are still playing music. If not, the last file has been loaded, and the file handle is closed. */ if(mpeg_file >= 0) { /* Update the watermark debug level */ if(unplayed_space_left < lowest_watermark_level) lowest_watermark_level = unplayed_space_left; DEBUGF("DMA underrun.\n"); dma_underrun = true; } else { DEBUGF("No more MP3 data. Stopping.\n"); queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0); playing = false; is_playing = false; } *psize = 0; /* no more transfer */ } } wake_up_thread();}static int add_track_to_tag_list(char *filename){ struct id3tag *t = NULL; int i; /* find a free tag */ for (i=0; i < MAX_ID3_TAGS_MASK; i++ ) if ( !_id3tags[i].used ) t = &_id3tags[i]; if(t) { /* grab id3 tag of new file and remember where in memory it starts */ if(mp3info(&(t->id3), filename)) { DEBUGF("Bad mp3\n"); return -1; } t->mempos = mp3buf_write; t->id3.elapsed = 0; if(!append_tag(t)) { DEBUGF("Tag list is full\n"); } else t->used = true; } else { DEBUGF("No memory available for id3 tag"); } return 0;}/* If next_track is true, opens the next track, if false, opens prev track */static int new_file(int steps){ int max_steps = playlist_amount(); int start = num_tracks_in_memory() - 1; if (start < 0) start = 0; do { char *trackname; trackname = playlist_peek( start + steps ); if ( !trackname ) return -1; DEBUGF("playing %s\n", trackname); mpeg_file = open(trackname, O_RDONLY); if(mpeg_file < 0) { DEBUGF("Couldn't open file: %s\n",trackname); steps++; /* Bail out if no file could be opened */ if(steps > max_steps) return -1; } else { int new_tag_idx = tag_write_idx; if(add_track_to_tag_list(trackname)) { /* Bad mp3 file */ steps++; close(mpeg_file); mpeg_file = -1; } else { /* skip past id3v2 tag */ lseek(mpeg_file, id3tags[new_tag_idx]->id3.first_frame_offset, SEEK_SET); id3tags[new_tag_idx]->id3.index = steps; id3tags[new_tag_idx]->id3.offset = 0; if(id3tags[new_tag_idx]->id3.vbr) /* Average bitrate * 1.5 */ recalculate_watermark( (id3tags[new_tag_idx]->id3.bitrate * 3) / 2); else recalculate_watermark( id3tags[new_tag_idx]->id3.bitrate); } } } while ( mpeg_file < 0 ); return 0;}static void stop_playing(void){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -