pass mp3 file through program

The attached code takes and mp3 file and converts it from 16bits to 8eight bits as well sends the PCM through the serial port. I was able to compile it in MSVC 6, but I am having difficulty loading an mp3 file. I tried loading an mp3 file with the following line:
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;
}


#define SOURCE_MP3 "song.mp3"

but this returns several compiling errors:

C:\Documents and Settings\student\Desktop\acm_mp3.cpp(79) : error C2143: syntax error : missing ')' before 'string'
C:\Documents and Settings\student\Desktop\acm_mp3.cpp(79) : error C2143: syntax error : missing ';' before 'string'
C:\Documents and Settings\student\Desktop\acm_mp3.cpp(79) : fatal error C1004: unexpected end of file found

If I comment the #define SOURCE_MP3 "song.mp3" line the program compiles but a dialog appears and reads "argument required (mp3 file)!"

Any suggestions would be greatly appreciated!
Macros are evil.

There's a semicolon at the end of your #define SOURCE_MP3 line. Get rid of it.


Or better yet change your #define to a constant:

 
static const char* SOURCE_MP3 = "song.mp3";

Thanks for the suggestion Disch! I changed my #define to a constant and that eliminated several errors, but there is one more which reads:

64: 'CreateFileW' : cannot convert parameter 1 from 'const char [6]' to 'LPCWSTR'
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

When I double click the error it points to the following line:

hComm = CreateFile("COM1:", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

What is happening? I've read my c++ textbook, but I don't know how to eliminate this error?

Any suggestions?
Well; that depends. Which of those is a 6 element character array constant?
Unicode error. I'm in the midst of writing an Aritcle on this very topic.

You need to do one of the following. Note these are listed in order of recommendtation. (#1 is the preferred solution)

1) Use Win32 Unicode friendly strings (wide or tchar):
 
CreateFile( _T("COM1:")  //...  <--- note the _T() 


2) Explicitly call the non-Unicode version of CreateFile:
 
CreateFileA( "COM1:" // <---- note the A in CreateFileA 


3) Don't build in Unicode. Either #undef UNICODE before you include windows.h, or change your project settings to not build in unicode. The latter solution is preferable.


EDIT:

Actually, since you're using char* all over the place, you pretty much are destroying Unicode possibilities. The easiest route would be #3... but then you won't have a Unicode friendly program (won't be able to open filenames with foreign characters in the name).

A better solution would be to be Unicode friendly, but it might take a bit of work. I should have my article finished by today if you're interested in learning.
Last edited on
I just read the wiki page on Unicode since I was not that familiar with the terminology. It's a very interesting concept and it makes a lot of sense. Please point me to your article so I can become more familiar with Unicode.

I'm a little short on time to complete this code; I would like to finish it by tomorrow. But after my deadline, it would be interesting to make this code UNICODE friendly when I have more freedom.

I just want to make sure that I understand what you have suggested. I can either 1)include #undef UNICODE before including windows.h 2) use CreateFileA( "COM1:" 3) change project settings or 4) make it UNICODE friendly.

Another question, how does using char* make this code non-UNICODE friendly?
change your project settings to not build in unicode. The latter solution is preferable.
All that really does is tell the compiler to not define UNICODE.

1)include #undef UNICODE before including windows.h
No.
1
2
3
4
#ifdef UNICODE
#undef UNICODE
#endif
#include <windows.h> 


Another question, how does using char* make this code non-UNICODE friendly?
Because the wide character versions take pointers to wchar_t.
Please point me to your article so I can become more familiar with Unicode.


It's not perfect, but here you go:

http://cplusplus.com/forum/articles/16820/
Thanks, its an interesting read.

I was able to compile the program with the offered suggestions. Unfortunately the other problem that I encountered pertained to the line 11 when I removed the forward slashes. I received a compile error. I tired changing the line to static const char* output.pcm "c:\\dump.pcm" but this produces the error C2143.

Anny suggestions?
You can't have a . in an identifier name

1
2
3
static const char output_pcm = "c:\\dump.pcm";
//  "output_pcm" is fine
//  "output.pcm" is bad 
Thanks, I fixed this error. I deleted the forward slashes from lines 11 and 168 and still receive the following errors which point to lines 10&11:

C:\Documents and Settings\student\Desktop\acm_mp3.cpp(10) : error C2059: syntax error : 'string'
C:\Documents and Settings\student\Desktop\acm_mp3.cpp(10) : error C2143: syntax error : missing ';' before 'string'
C:\Documents and Settings\student\Desktop\acm_mp3.cpp(11) : error C2143: syntax error : missing ';' before 'string'
C:\Documents and Settings\student\Desktop\acm_mp3.cpp(11) : fatal error C1004: unexpected end of file found

I'm at my wits end! What else am I missing?
A * between 'const char' and the identifier?
Topic archived. No new replies allowed.