⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 plam编程
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * 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(&notifyParam, 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 + -