📄 main.c
字号:
/*
* MiniMP3.c
*
* Main File for MiniMp3
*
* This wizard-generated code is based on code adapted from the
* stationery files distributed as part of the Palm OS SDK
*
* Copyright (c) 1999-2004 PalmOne, Inc. or its subsidiaries.
* All rights reserved.
*/
#include <PalmOS.h>
#include <VFSMgr.h>
#include <Hs.h>
#include "mp3.h"
#include "id3.h"
#include "MiniMP3.h"
#include "MiniMP3Rsc.h"
#include "Common.h"
#include "FileBrowserForm.h"
#include "FileBrowserFormRsrc.h"
#include <PalmOneCodecPluginMgr.h>
#include <PalmOneCodecFormat.h>
#define ourMinVersion sysMakeROMVersion(3,0,0,sysROMStageDevelopment,0)
#define kPalmOS20Version sysMakeROMVersion(2,0,0,sysROMStageDevelopment,0)
#define SRC_SIZE 1024
#define DEST_SIZE 32768
/**
* MP3 Info
*/
typedef struct
{
Boolean hasID3v1; // True if has ID3v1 tag
Boolean hasID3v2; // True if has ID3v2 tag
Boolean hasXing; // True if has Xing header
ID3v1Tag id3; // ID3v1 tag
MP3Version version; // MP3 version
MP3Layer layer; // MP3 Layer
UInt32 bitRate; // Average bit rate
UInt16 frameSize; // Average Frame Size
UInt16 sampleRate; // Sample rate
Boolean VBR; // True is VBR file
MP3Mode channelMode; // Channel mode (STEREO, JOINT_STEREO...)
} MP3Info;
/**
* File Info
*/
typedef struct
{
Char filePath[256]; // Contains filename + full path
FileRef fileRef; // File ref
UInt32 fileSize; // File size
UInt32 fileDataSize; // Dile data size (=fileEndOffset-fileStartOffset)
UInt32 fileStartOffset;// File start offset
UInt32 fileEndOffset; // File end offset
} FileInfo;
/** Mini info structure. */
typedef struct _MiniInfo MiniInfo;
/**
* Mini info structure.
* Stores all the needed info for the sound callback.
*/
struct _MiniInfo
{
UInt16 CodecMgrLibRefNum; // MP3 library
MP3Info mp3Info; // MP3 info
FileInfo fileInfo; // File info
SndStreamRef sndRef; // Stream reference
PalmCodecSession session; // MP3 session
Int32 volume; // Stream volume
Int8 *srcBufferP; // The input buffer.
UInt32 srcBufferSize; // Size of the input buffer
UInt32 srcDataSize; // Data in source buffer
UInt32 srcOffset; // Offset in source buffer
Int8 *destBufferP; // Decoded buffer output
UInt32 destBufferSize; // Size the destination buffer
UInt32 destDataSize; // Data in decoded buffer
UInt32 destOffset; // Offset in the destination buffer
UInt16 cardNo;
LocalID dbID;
};
/**
* MiniInfo global
*/
static MiniInfo gMiniInfo;
static UInt16 gOldAutoOffTime = 0;
static Char gAlertString[80];
UInt32 temp = 0;
/***********************************************************************
*
* FUNCTION: PrvNewStreamCallback
*
* DESCRIPTION: New callback.
*
* PARAMETERS:
*
* RETURNED: Error code
*
***********************************************************************/
#define THRESHOLD (1450) // That's the size of the biggest possible frame
static Err PrvNewStreamCallback(void *userData, SndStreamRef stream, void *buffer, UInt32 frameCount)
{
Err err = errNone;
UInt32 read = 0;
UInt32 offset = 0;
MiniInfo *miniInfoP = (MiniInfo*)userData;
UInt32 numChannels = (miniInfoP->mp3Info.channelMode==MP3_SINGLE_CHANNEL)?1:2;
// Calculate buffer length
frameCount *= 2 * numChannels;
// Check current output buffer data size
if(miniInfoP->destDataSize > frameCount)
{
// Copy output buffer
MemMove(buffer, miniInfoP->destBufferP + miniInfoP->destOffset, frameCount);
miniInfoP->destOffset += frameCount;
miniInfoP->destDataSize -= frameCount;
}
else
{
UInt32 inSize = 0;
UInt32 outSize = 0;
UInt32 endDataSize = 0;
// Copy the output left over
MemMove(buffer, miniInfoP->destBufferP + miniInfoP->destOffset, miniInfoP->destDataSize);
offset = miniInfoP->destDataSize;
miniInfoP->destOffset = 0;
miniInfoP->destDataSize = 0;
// Check the input buffer
if(miniInfoP->srcDataSize < THRESHOLD) {
// Move the end of the buffer to the front
MemMove(miniInfoP->srcBufferP, miniInfoP->srcBufferP + miniInfoP->srcOffset, miniInfoP->srcDataSize);
miniInfoP->srcOffset = 0;
// Read more data from file
err = VFSFileRead(miniInfoP->fileInfo.fileRef,
miniInfoP->srcBufferSize - miniInfoP->srcDataSize,
miniInfoP->srcBufferP + miniInfoP->srcDataSize, &read);
// EOF is not an error
if(err == vfsErrFileEOF)
err = errNone;
miniInfoP->srcDataSize += read;
}
inSize = miniInfoP->srcDataSize;
outSize = miniInfoP->destBufferSize;
// Decode data from the input buffer
err = CodecMgrEncodeDecode(miniInfoP->CodecMgrLibRefNum, miniInfoP->session,
miniInfoP->srcBufferP + miniInfoP->srcOffset, &inSize,
miniInfoP->destBufferP, &outSize);
// Check how much was decoded
if(err || outSize == 0)
{
SysNotifyParamType notifyParam;
// Set the notification info
notifyParam.notifyType = appFileCreator;
notifyParam.broadcaster = appFileCreator;
notifyParam.handled = false;
notifyParam.notifyDetailsP = NULL;
// Send a notification to stop playing
err = SysNotifyBroadcastDeferred(¬ifyParam, 0);
SndStreamStop(stream);
}
miniInfoP->srcOffset += inSize;
miniInfoP->srcDataSize -= inSize;
miniInfoP->destDataSize = outSize;
endDataSize = frameCount - offset;
endDataSize = (miniInfoP->destDataSize < endDataSize)?miniInfoP->destDataSize:endDataSize;
// Finish writing to the sound buffer
MemMove((void*)((Int8*)buffer + offset), miniInfoP->destBufferP, endDataSize);
miniInfoP->destOffset += endDataSize;
miniInfoP->destDataSize -= endDataSize;
}
return err;
}
#if 0
#pragma mark -
#endif
/**
* Shows Alert Box
*/
static void PrvAlert( Char* string)
{
FrmCustomAlert( InfoAlert, string,"","");
}
/**
* Open a file
*/
static Err PrvFileOpen(MiniInfo* miniInfoP)
{
Err err = errNone;
UInt32 volumeIterator = 0;
UInt16 firstVolume = 0;
// Get first card
volumeIterator = vfsIteratorStart;
err = VFSVolumeEnumerate(&firstVolume, &volumeIterator);
if( err == expErrEnumerationEmpty ) {
StrCopy( gAlertString, "Error enumerating Volume");
goto Done;
}
// If we have a file path, open the file
if(miniInfoP->fileInfo.filePath )
{
err = VFSFileOpen(firstVolume, (Char*)miniInfoP->fileInfo.filePath, vfsModeRead, &miniInfoP->fileInfo.fileRef);
if( err )
{
StrCopy( gAlertString, "File Open err. Select a Mp3/2 file");
goto Done;
}
// Store the file size
err = VFSFileSize(miniInfoP->fileInfo.fileRef , &miniInfoP->fileInfo.fileSize);
if( err )
{
StrCopy( gAlertString, "File Size Error");
goto Done;
}
miniInfoP->fileInfo.fileStartOffset = 0;
miniInfoP->fileInfo.fileEndOffset = miniInfoP->fileInfo.fileSize;
}
Done:
if(err)
PrvAlert( gAlertString );
return err;
}
/**
* Parse MP3 file
*/
static Err PrvParseMP3(MiniInfo* miniInfoP)
{
Err err = errNone;
Char buffer[128];
FrameInfo frameInfo;
UInt32 headerSize = 0, header = 0, byteRead = 0, byteCount = 0;
StrCopy( gAlertString, "Error in ParseMP3, Corrupt Mp3/2 file");
// Check for ID3v1
err = VFSFileSeek(miniInfoP->fileInfo.fileRef, vfsOriginEnd , -128);
if( err ) goto Done;
err = VFSFileRead(miniInfoP->fileInfo.fileRef, 128, &buffer, &byteRead);
if( err ) goto Done;
miniInfoP->mp3Info.hasID3v1 = CheckID3v1((Char*)buffer, byteRead, &miniInfoP->mp3Info.id3);
// Set the file offset (we don't want to send the tags to the decoder)
if( miniInfoP->mp3Info.hasID3v1 ) {
miniInfoP->fileInfo.fileEndOffset -= 128;
}
// Check for ID3v2
err = VFSFileSeek(miniInfoP->fileInfo.fileRef, vfsOriginBeginning , 0);
if( err ) goto Done;
err = VFSFileRead(miniInfoP->fileInfo.fileRef, 10, buffer, &byteRead);
if( err ) goto Done;
miniInfoP->mp3Info.hasID3v2 = CheckID3v2((Char*)buffer, byteRead, &headerSize);
// Set the file offset (we don't want to send the tags to the decoder)
if( miniInfoP->mp3Info.hasID3v2 ) {
miniInfoP->fileInfo.fileStartOffset = headerSize;
}
// Set the file data size
miniInfoP->fileInfo.fileDataSize = miniInfoP->fileInfo.fileEndOffset - miniInfoP->fileInfo.fileStartOffset;
//
// Now decode the first header (no VBR!!!)
//
// Rewind to the beginning of the data
err = VFSFileSeek(miniInfoP->fileInfo.fileRef, vfsOriginBeginning , miniInfoP->fileInfo.fileStartOffset);
if( err ) goto Done;
// Read the frame header
err = VFSFileRead(miniInfoP->fileInfo.fileRef, 4, &header, &byteRead);
if( err ) goto Done;
// Decode the header
if( DecodeMP3Header( header, &frameInfo) )
{
miniInfoP->mp3Info.version = frameInfo.version;
miniInfoP->mp3Info.layer = frameInfo.layer;
miniInfoP->mp3Info.bitRate = frameInfo.bitRate;
miniInfoP->mp3Info.channelMode = frameInfo.channelMode;
miniInfoP->mp3Info.sampleRate = frameInfo.sampleRate;
temp = frameInfo.length;
}
else
{
err = -1;
goto Done;
}
// Rewind to the start of the data
err = VFSFileSeek(miniInfoP->fileInfo.fileRef, vfsOriginBeginning , miniInfoP->fileInfo.fileStartOffset);
if( err ) goto Done;
Done:
if( err )
PrvAlert( gAlertString );
return err;
}
/**
* Create stream.
*
*
*/
static Err PrvCreateStream(MiniInfo* miniInfoP)
{
Err err = errNone;
UInt8 numChannel = (miniInfoP->mp3Info.channelMode==MP3_SINGLE_CHANNEL)?1:2;
// Use regualr stream
err = SndStreamCreate(&miniInfoP->sndRef, sndOutput, miniInfoP->mp3Info.sampleRate,
sndInt16Little, (numChannel==1)?sndMono:sndStereo,
&PrvNewStreamCallback, miniInfoP, 2048 / numChannel, false);
if(err)
{
StrCopy( gAlertString, "Error creating stream");
goto Done;
}
if( miniInfoP->mp3Info.layer == LAYER3 )
{
// Create an MP3 session
err = CodecMgrCreateSession(miniInfoP->CodecMgrLibRefNum,
palmCodecAudioMP3, NULL, palmCodecAudioPCM, NULL, &miniInfoP->session);
}
if(err)
StrCopy( gAlertString, "Error creating CPM session");
Done:
if(err)
PrvAlert( gAlertString );
return err;
}
/**
* Stop the current playing file.
*/
static void PrvStopFile(MiniInfo *miniInfoP)
{
Err err = errNone;
// Stop the stream
if(miniInfoP->sndRef)
err = SndStreamStop(miniInfoP->sndRef);
// Delete the stream
if(miniInfoP->sndRef) {
err = SndStreamDelete(miniInfoP->sndRef);
miniInfoP->sndRef = NULL;
}
// Delete the MP3 session
if(miniInfoP->session) {
err = CodecMgrDeleteSession(miniInfoP->CodecMgrLibRefNum, &miniInfoP->session);
}
// Close the file
if(miniInfoP->fileInfo.fileRef) {
VFSFileClose(miniInfoP->fileInfo.fileRef);
miniInfoP->fileInfo.fileRef = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -