1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
|
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#include <mmreg.h>
#include <msacm.h>
#pragma comment (lib, "msacm32.lib")
#define MP3_BLOCK_SIZE 522
#define SOURCE_MP3 "sound.mp3";
//#define output.pcm "c:\\dump.pcm"
HANDLE hComm;
void OpenComm()
{
DCB dcb;
hComm = CreateFile("COM1:", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hComm==INVALID_HANDLE_VALUE) exit(1);
if(!SetupComm(hComm, 4096, 4096)) exit(1);
if(!GetCommState(hComm, &dcb)) exit(1);
dcb.BaudRate = 115200;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = 0;
if(!SetCommState(hComm, &dcb)) exit(1);
}
void CloseComm()
{
CloseHandle(hComm);
}
DWORD WriteComm(BYTE* buf, int len)
{
DWORD nSend;
if(!WriteFile(hComm, buf, len, &nSend, NULL)) exit(1);
return nSend;
}
////////////////////////////////////////////////////////////
typedef struct mpeglayer3waveformat_tag1
{
WAVEFORMATEX wfx;
WORD wID;
DWORD fdwFlags;
WORD nBlockSize;
WORD nFramesPerBlock;
WORD nCodecDelay;
} MPEGLAYER3WAVEFORMAT1;
typedef MPEGLAYER3WAVEFORMAT FAR *LPMPEGLAYER3WAVEFORMAT;
#define MPEGLAYER3_WFX_EXTRA_BYTES 12
#define WAVE_FORMAT_MPEGLAYER3 0x0055
#define MPEGLAYER3_ID_UNKNOWN 0
#define MPEGLAYER3_ID_MPEG 1
#define MPEGLAYER3_ID_CONSTANTFRAMESIZE 2
#define MPEGLAYER3_FLAG_PADDING_ISO 0x00000000
#define MPEGLAYER3_FLAG_PADDING_ON 0x00000001
#define MPEGLAYER3_FLAG_PADDING_OFF 0x00000002
////////////////////////////////////////////////////////////
HACMSTREAM g_mp3stream = NULL;
typedef SHORT* LPSHORT;
BYTE PCM[0x200000]; // 2MB reserved for the decoded PCM
int iPCM = 0;
int DecodeMP3(char* SOURCE_MP3)
{
MMRESULT mmr;
// find the biggest format size
DWORD maxFormatSize = 0;
mmr = acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &maxFormatSize);
// define desired output format
LPWAVEFORMATEX waveFormat = (LPWAVEFORMATEX) LocalAlloc(LPTR, maxFormatSize);
waveFormat->wFormatTag = WAVE_FORMAT_PCM;
waveFormat->nChannels = 2; // stereo
waveFormat->nSamplesPerSec = 44100; // 44.1kHz
waveFormat->wBitsPerSample = 16; // 16 bits
waveFormat->nBlockAlign = 4; // 4 bytes of data at a time are useful (1 sample)
waveFormat->nAvgBytesPerSec = 4 * 44100; // byte-rate
waveFormat->cbSize = 0; // no more data to follow
// define MP3 input format
LPMPEGLAYER3WAVEFORMAT mp3format = (LPMPEGLAYER3WAVEFORMAT) LocalAlloc(LPTR, maxFormatSize);
mp3format->wfx.cbSize = MPEGLAYER3_WFX_EXTRA_BYTES;
mp3format->wfx.wFormatTag = WAVE_FORMAT_MPEGLAYER3;
mp3format->wfx.nChannels = 2;
mp3format->wfx.nAvgBytesPerSec = 128 * (1024 / 8); // not really used but must be one of 64, 96, 112, 128, 160kbps
mp3format->wfx.wBitsPerSample = 0; // MUST BE ZERO
mp3format->wfx.nBlockAlign = 1; // MUST BE ONE
mp3format->wfx.nSamplesPerSec = 44100; // 44.1kHz
mp3format->fdwFlags = MPEGLAYER3_FLAG_PADDING_OFF;
mp3format->nBlockSize = MP3_BLOCK_SIZE; // voodoo value #1
mp3format->nFramesPerBlock = 1; // MUST BE ONE
mp3format->nCodecDelay = 1393; // voodoo value #2
mp3format->wID = MPEGLAYER3_ID_MPEG;
g_mp3stream = NULL;
mmr = acmStreamOpen(&g_mp3stream, // open an ACM conversion stream
NULL, // querying all ACM drivers
(LPWAVEFORMATEX) mp3format, // converting from MP3
waveFormat, // to WAV
NULL, // with no filter
0, // or async callbacks
0, // (and no data for the callback)
0 // and no flags
);
LocalFree(mp3format);
LocalFree(waveFormat);
switch(mmr ) {
case MMSYSERR_NOERROR:
break; // success!
case MMSYSERR_INVALPARAM:
assert(!"Invalid parameters passed to acmStreamOpen");
return E_FAIL;
case ACMERR_NOTPOSSIBLE:
assert(!"No ACM filter found capable of decoding MP3");
return E_FAIL;
default:
assert(!"Some error opening ACM decoding stream!");
return E_FAIL;
}
// MP3 stream converter opened correctly
// now, let's open a file, read in a bunch of MP3 data, and convert it!
// open file
FILE *fpIn = fopen(SOURCE_MP3,"rb");
if(fpIn == NULL )
{
assert(!"can't open MP3 file!");
return E_FAIL;
}
// find out how big the decompressed buffer will be
unsigned long rawbufsize = 0;
mmr = acmStreamSize(g_mp3stream, MP3_BLOCK_SIZE, &rawbufsize, ACM_STREAMSIZEF_SOURCE);
assert(mmr == 0);
assert(rawbufsize > 0);
// allocate our I/O buffers
LPBYTE mp3buf = (LPBYTE) LocalAlloc(LPTR, MP3_BLOCK_SIZE);
LPBYTE rawbuf = (LPBYTE) LocalAlloc(LPTR, rawbufsize);
// prepare the decoder
ACMSTREAMHEADER mp3streamHead;
ZeroMemory(&mp3streamHead, sizeof(ACMSTREAMHEADER ));
mp3streamHead.cbStruct = sizeof(ACMSTREAMHEADER);
mp3streamHead.pbSrc = mp3buf;
mp3streamHead.cbSrcLength = MP3_BLOCK_SIZE;
mp3streamHead.pbDst = rawbuf;
mp3streamHead.cbDstLength = rawbufsize;
mmr = acmStreamPrepareHeader(g_mp3stream, &mp3streamHead, 0);
assert(mmr == 0);
//FILE *fpOut = fopen("output.pcm", "wb"); if(fpOut == NULL ){assert(!"can't output output PCM!");return E_FAIL;}
while(1)
{
// suck in some MP3 data
DWORD count = fread(mp3buf, 1, MP3_BLOCK_SIZE, fpIn);
if(count != MP3_BLOCK_SIZE ) break;
// convert the data
mmr = acmStreamConvert(g_mp3stream, &mp3streamHead, ACM_STREAMCONVERTF_BLOCKALIGN);
assert(mmr == 0);
// convert 16-bits 44KHz stereo to 8-bits 11KHz mono
int newbuflength = mp3streamHead.cbDstLengthUsed/16;
LPSHORT shortbuf = (LPSHORT)rawbuf;
for(int i=0; i<newbuflength; i++)
{
int acc = 0;
for(int j=0; j<8; j++) acc += *shortbuf++;
// rawbuf[i] = acc/256/8 + 0x80;
if(iPCM<sizeof(PCM)) PCM[iPCM++] = acc/256/8 + 0x80;
}
if(iPCM>=sizeof(PCM)) break;
// send to serial port
// WriteComm(rawbuf, newbuflength);
// printf(".");
// write the decoded PCM to disk
// count = fwrite(rawbuf, 1, newbuflength, fpOut);
};
fclose(fpIn);
//fclose(fpOut);
mmr = acmStreamUnprepareHeader(g_mp3stream, &mp3streamHead, 0);
assert(mmr == 0);
LocalFree(rawbuf);
LocalFree(mp3buf);
mmr = acmStreamClose(g_mp3stream, 0);
assert(mmr == 0);
return S_OK;
}
int main(int argc, char *argv[])
{
if(argc!=2)
{
printf("argument required (mp3 file)!\n");
exit(1);
}
printf("Playing %s\n", argv[1]);
OpenComm();
printf("decoding... "); DecodeMP3(argv[1]);
printf("playing... "); WriteComm(PCM, iPCM);
CloseComm();
return 0;
}
|