📄 mp3pc.c
字号:
StreamFileC();
FINDFILE_OFSET = ((u16)SEC_PER_CLUS)<<9;
// Loop until we've counted through the required number of file records
// Note that filecount can start at zero, whereas N and NN start at 1.
while (filecount < N) {
// If we're at the (N-1)th file directory entry, put its directory cluster number in FINDFILE_PREV_CLUS
if (filecount == (NN-1))
FINDFILE_PREV_CLUS = FINDFILE_CLUS;
// if clusterbytecount == numberofbytespercluster, we need to read the 4-byte cluster number out of the data Q,
// and reset the OffsetIntoCluster counter. FYI, a multiply by 512 is a left-shift of 9 bits.
if (FINDFILE_OFSET == ((u16)SEC_PER_CLUS)<<9) {
// wait until 4 bytes in data Q
while ( Q_HowMuchDataC((u08*)&MP3DATAQ[0]) < 4 ) {
StreamFileC();
if ( (STREAMFILE_ST==StreamFile_St_Idle) && (Q_HowMuchDataC((u08*)&MP3DATAQ[0])<4) )
return FindFile_err;
}
// extract cluster number low-byte first, reset OffsetIntoCluster counter, and continue along...
FINDFILE_CLUS = ((u32)Q_read_C((u08*)&MP3DATAQ[0])) + (((u32)Q_read_C((u08*)&MP3DATAQ[0]))<<8) + \
+ (((u32)Q_read_C((u08*)&MP3DATAQ[0]))<<16) + (((u32)Q_read_C((u08*)&MP3DATAQ[0]))<<24);
FINDFILE_OFSET = 0;
}
// Wait until 32 bytes in queue. If StreamFileC goes idle, return with error, because we've run out
// of directory data before we reached the required number of files. Possibly due to FAT corruption.
while ( Q_HowMuchDataC((u08*)&MP3DATAQ[0]) < 32 ) {
StreamFileC();
if ( (STREAMFILE_ST==StreamFile_St_Idle) && (Q_HowMuchDataC((u08*)&MP3DATAQ[0])<32) )
return FindFile_err;
}
// We now have 32 bytes in the queue; a directory entry's worth. Read them out of
// the queue, keeping a few of them for later review, discarding the rest. The first 12 bytes in
// the queue are the short filename (8.3) and the file attributes. If the first byte is zero,
// return, also telling StreamFileC to stop, because there are no more files in this directory.
firstchar = Q_read_C((u08*)&MP3DATAQ[0]); // get first character of filename
if (firstchar == 0x00 ) {
STREAMFILE_CMD = StreamFile_Cmd_Stop; // tell StreamFileC to stop, then
while (STREAMFILE_ST!=StreamFile_St_Idle) StreamFileC(); // wait until it's idle
return FindFile_err;
}
// put the 8 characters of the short filename into the filename array
FINDFILE_RET_NAME[0] = 12; // first array element is length
FINDFILE_RET_NAME[1] = firstchar;
FINDFILE_RET_NAME[2] = Q_read_C((u08*)&MP3DATAQ[0]); // get 2nd character of filename
FINDFILE_RET_NAME[3] = Q_read_C((u08*)&MP3DATAQ[0]); // get 3rd character of filename
FINDFILE_RET_NAME[4] = Q_read_C((u08*)&MP3DATAQ[0]); // get 4th character of filename
FINDFILE_RET_NAME[5] = Q_read_C((u08*)&MP3DATAQ[0]); // get 5th character of filename
FINDFILE_RET_NAME[6] = Q_read_C((u08*)&MP3DATAQ[0]); // get 6th character of filename
FINDFILE_RET_NAME[7] = Q_read_C((u08*)&MP3DATAQ[0]); // get 7th character of filename
FINDFILE_RET_NAME[8] = Q_read_C((u08*)&MP3DATAQ[0]); // get 8th character of filename
extm = Q_read_C((u08*)&MP3DATAQ[0]);
extp = Q_read_C((u08*)&MP3DATAQ[0]);
ext3 = Q_read_C((u08*)&MP3DATAQ[0]); // hopefully these 3 characters are "MP3"
FINDFILE_RET_NAME[9] = '.';
FINDFILE_RET_NAME[10] = extm;
FINDFILE_RET_NAME[11] = extp;
FINDFILE_RET_NAME[12] = ext3;
FINDFILE_RET_NAME[13] = 0; // null-terminate file name array
attr = Q_read_C((u08*)&MP3DATAQ[0]); // get file attributes
for (i=8;i;i--)
Q_read_C((u08*)&MP3DATAQ[0]); // throwaway next 8 bytes in directory structure
// get 32-bit starting cluster number for file
FINDFILE_RET_CLUS = (((u32)Q_read_C((u08*)&MP3DATAQ[0]))<<16) + (((u32)Q_read_C((u08*)&MP3DATAQ[0]))<<24);
Q_read_C((u08*)&MP3DATAQ[0]);
Q_read_C((u08*)&MP3DATAQ[0]);
Q_read_C((u08*)&MP3DATAQ[0]);
Q_read_C((u08*)&MP3DATAQ[0]); // toss time&date of last write 4 bytes
FINDFILE_RET_CLUS += (((u32)Q_read_C((u08*)&MP3DATAQ[0]))) + (((u32)Q_read_C((u08*)&MP3DATAQ[0]))<<8);
// get 32-bit file size
FINDFILE_RET_SIZE = (((u32)Q_read_C((u08*)&MP3DATAQ[0]))) + (((u32)Q_read_C((u08*)&MP3DATAQ[0]))<<8) + \
(((u32)Q_read_C((u08*)&MP3DATAQ[0]))<<16) + (((u32)Q_read_C((u08*)&MP3DATAQ[0]))<<24);
// Increment filecount if we've found an MP3 file
if ( firstchar!=0xE5 && extm=='M' && extp=='P' && ext3=='3' && !(attr&0x1E) )
filecount++;
// increment OffsetIntoCluster by the number of bytes we've read
FINDFILE_OFSET += 32;
// give StreamFileC another chance to run, then loop back for the next directory entry
StreamFileC();
}
STREAMFILE_CMD = StreamFile_Cmd_Stop; // command StreamFileC to STOP; we're all done now
return FindFile_done;
}
void GetLongFileName (void)
/* WARNING: DOES NOT RETURN UNTIL COMPLETED - VERY VERY SLOW */
// Here's the magic routine. It gets the long filename for the current file off the disk and
// writes that name into the FINDFILE_RET_NAME structure. It works by looking at three FindNthMP3 / FindNthDir
// global variables: FINDFILE_CLUS, FINDFILE_PREV_CLUS, and FINDFILE_OFSET. _CLUS and _OFSET
// provide the location (cluster number and byte offset into that cluster) of the NEXT directory
// entry. Subtract 1 from this and you have the location of the last byte of the 8.3 filename directory
// entry for the current file. Directory entries are 32 bytes long; the entry before the 8.3 name is
// potentially the first of possibly several long-filename directory entries for our current file.
// (Note the "potentially" and "possibly". There might not be any long filename directory entries for
// the current file, in which case we use the 8.3 name already provided by FindNthMP3. Or there might
// be one, two, or more long filename entries. We cannot make any assumptions what might be present.)
//
// So now that we know where the long filename directory entries begin (actually end), how do we get them?
// By telling StreamFile to stream a bunch of directory entry data, and then reading that data out of the
// queue backwards. StreamFile can stop streaming at _CLUS bytes _OFSET-32 (the -32 because we don't need
// the 8.3 name) but where to start? Start streaming from the previous cluster; the one before _CLUS,
// which is _PREV_CLUS. This is to ensure if the longname crosses a cluster boundary (which it can do
// and sometimes does) we'll still get it all. Often _CLUS and _PREV_CLUS are the same, which speeds
// things up.
{
u16 i, DirCnt, StreamBytes;
u08 r[15];
u08 attr, temp;
// Calculate how many bytes to tell StreamFile to stream from the disk directory data. This is
// dependant upon whether FINDFILE_PREV_CLUS and FINDFILE_CLUS are the same or not. If we need to
// stream the previous cluster, there are SEC_PER_CLUS sectors in a cluster, and 512 bytes
// in a sector.
StreamBytes = FINDFILE_OFSET-32; // don't need the 8.3 directory entry
if (FINDFILE_PREV_CLUS != FINDFILE_CLUS)
StreamBytes += ((u16)SEC_PER_CLUS) << 9; // stream previous cluster if required
// Tell StreamFile to stream the directory data into the MP3 data queue.
// if queue not large enough then do some dummy reads to make space
STREAMFILE_CMD = StreamFile_Cmd_Stop;
while (STREAMFILE_ST != StreamFile_St_Idle) StreamFileC(); /* ensure StreamFile is idle */
STREAMFILE_FILESZ = StreamBytes; /* stream this many directory bytes */
STREAMFILE_CLUS = FINDFILE_PREV_CLUS; /* starting from this directory cluster */
STREAMFILE_QPOINTER = &MP3DATAQ[0]; /* point StreamFile to the MP3 Data queue */
Q_clear_C((u08*)&MP3DATAQ[0]); /* ensure that Q is empty (yes I'm paranoid) */
STREAMFILE_CMD = StreamFile_Cmd_Stream; /* tell StreamFile to stream the file to the Q */
StreamFileC(); /* get StreamFile started */
// determine how many dummy reads (i) we may have to do (if MP3 q too small to hold all the data)
i = 0;
if (StreamBytes > (MP3DATAQ_size - 10))
i = StreamBytes - MP3DATAQ_size + 10;
// stream directory into queue; do dummy reads if required
while (STREAMFILE_ST != StreamFile_St_Idle) { /* loop until StreamFile finished streaming */
StreamFileC();
if (i) { /* if we need to do dummy read from queue... */
Q_read_C ((u08*)&MP3DATAQ[0]); /* attempt dummy read */
if (ReadQstatus == Q_OK) i--; /* if dummy read successful decrement dummy read counter */
}
}
// At this point the directory entries are in the queue. Now we can read them out. We need to
// define the maximum number of long filename directory entries (DirCnt) we'll permit, which is based
// upon the amount of memory space we allocated for the file name string. We read them out one
// set of 32-bytes directory entry at a time, looping until we've done them all.
DirCnt = FindFile_NumLongDirs;
while (DirCnt) {
// read a 32-byte directory entry backwards out of the queue
// note that characters are in 16-bit unicode; we only care about the first byte
r[14] = 0; // ensure r[] is null-terminated
Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // toss directory offset byte 31
r[13] = Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // character 13 in this directory entry
Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // toss directory offset byte 29
r[12] = Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // character 12 in this directory entry
Q_Read_FILO_C((u08*)&MP3DATAQ[0]);
Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // offsets 26-27 should be zero - we'll ignore
Q_Read_FILO_C((u08*)&MP3DATAQ[0]);
r[11] = Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // character 11 in this directory entry
Q_Read_FILO_C((u08*)&MP3DATAQ[0]);
r[10] = Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // character 10 in this directory entry
Q_Read_FILO_C((u08*)&MP3DATAQ[0]);
r[9] = Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // character 9 in this directory entry
Q_Read_FILO_C((u08*)&MP3DATAQ[0]);
r[8] = Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // character 8 in this directory entry
Q_Read_FILO_C((u08*)&MP3DATAQ[0]);
r[7] = Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // character 7 in this directory entry
Q_Read_FILO_C((u08*)&MP3DATAQ[0]);
r[6] = Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // character 6 in this directory entry
Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // ignore checksum in offset 13
Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // should be zero in offset 12 - we'll ignore
attr = Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // directory attributes in offset 11
Q_Read_FILO_C((u08*)&MP3DATAQ[0]);
r[5] = Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // character 5 in this directory entry
Q_Read_FILO_C((u08*)&MP3DATAQ[0]);
r[4] = Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // character 4 in this directory entry
Q_Read_FILO_C((u08*)&MP3DATAQ[0]);
r[3] = Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // character 3 in this directory entry
Q_Read_FILO_C((u08*)&MP3DATAQ[0]);
r[2] = Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // character 2 in this directory entry
Q_Read_FILO_C((u08*)&MP3DATAQ[0]);
r[1] = Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // character 1 in this directory entry
r[0] = Q_Read_FILO_C((u08*)&MP3DATAQ[0]); // offset zero is directory ordinal number
if ((attr & 0x0f) != 0x0f) return; // finish if this not a long directory entry
// If the first directory entry is a long filename entry, zero the filename byte count so that the
// long filename can be entered. Otherwise leave it as it is, so the 8.3 name put in by FindNthMP3
// remains. Note that if the code executes to this point, we do have a long filename entry, because
// the test above (if... return) failed. Checking the value of DirCnt informs us if we're here for
// the first time or not.
if (DirCnt == FindFile_NumLongDirs)
FINDFILE_RET_NAME[0] = 0; // zero length byte - fill name from start of buffer
// copy long filename characters into the filename buffer FINDFILE_RET_NAME[]
// the first byte in that filename buffer is the length
// note that longfilenames on the disk (now in r[]) are null-terminated. r[1] is the first character.
// FINDFILE_RET_NAME[0] is the number of characters in array, not including length or NULL
i = 1;
temp = FINDFILE_RET_NAME[0]; // number of bytes already in filename buffer
do
FINDFILE_RET_NAME[temp+i] = r[i];
while (r[i++]);
FINDFILE_RET_NAME[0] = temp + i - 2; // update length byte to reflect characters just added
if (r[0] & 0x40) return; // if this was last long filename dir entry then finish
DirCnt--; // else decrement directory count & loop again
}
}
void FormatFileNameString (u08 TruncEnd)
// This routine formats the filename string to make the file name look better when displayed
// on the LCD. It tries to prevent words from breaking over two lines.
// Remember the format of the string: FINDFILE_RET_NAME[0] contains a length byte (which we don't
// care about; the first character in the string is at FINDFILE_RET_NAME[1].
//
// There are three characters we're interested in: the space, the hyphen, and the period. Basically,
// a space at the end of a line is good; a hyphen at the end of a line is good, and a period at the
// beginning of the next line is good. If one of these 3 conditions doesn't exist for a given line,
// try and make it so. Additionally, we don't want a line to start with a space.
//
// TruncEnd says how many characters to remove from end of string; useful for removing .mp3 extensions
// from the filename. (ie set this to 4 to remove a .mp3 extension).
{
u08 *tempptr;
u08 freespace, backcount;
// first we need to know how many characters we can insert; is the string already full?
// freespace will end up containing number of free spaces in the string
// max number of characters is 96 (24 chars x 4 lines)
tempptr = (u08*)&FINDFILE_RET_NAME[1];
freespace = 0;
while (*tempptr) {
freespace++; // freespace counts number of characters to null
tempptr++;
}
freespace = 96 - freespace; // free string space equals 96 - number used characters
// remove TruncEnd characters from end of filename string
// note that tempptr is pointing to the null at the end of the string
// ensure sufficient characters in string so we can perform truncation
// number of characters in the string = 96 - freespace
if (TruncEnd && ((96-freespace)>TruncEnd)) {
tempptr = tempptr - TruncEnd;
*tempptr = 0; // new null TruncEnd characters back; string is now shortened
freespace = freespace + TruncEnd; // we have some extra free space in the string buffer now
}
// PROCESS THE FIRST LINE (characters 1 - 24)
// Remove any spaces at the beginning of the line
while (FINDFILE_RET_NAME[1] == ' ') { // if first char is a space...
DeleteCharFromString((u08*)&FINDFILE_RET_NAME[1]); // then remove it
freespace++; // and we now have an extra place free in the string
}
// Now deal with the end of the line. This switch statement only inserts spaces, so don't bother even
// executing it if there's no free space in the string buffer.
if (freespace) {
switch (FINDFILE_RET_NAME[24]) {
case ' ': case '-': // space or hyphen at end of line is good
break;
case '.': // if period at end of line, move it to the next line
InsertCharInString((u08*)&FINDFILE_RET_NAME[24], ' ');
freespace--;
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -