mirror of
https://github.com/QB64Official/qb64.git
synced 2024-09-19 22:35:24 +00:00
178 lines
5 KiB
C
178 lines
5 KiB
C
|
// minimp3 example player application for Win32
|
||
|
// this file is public domain -- do with it whatever you want!
|
||
|
#define MAIN_PROGRAM
|
||
|
|
||
|
#include "libc.h"
|
||
|
#include "minimp3.h"
|
||
|
|
||
|
#define BUFFER_COUNT 8
|
||
|
|
||
|
static WAVEFORMATEX wf = {
|
||
|
1, // wFormatTag
|
||
|
0, // nChannels
|
||
|
0, // nSamplesPerSec
|
||
|
0, // nAvgBytesPerSec
|
||
|
4, // nBlockAlign
|
||
|
16, // wBitsPerSample
|
||
|
sizeof(WAVEFORMATEX) // cbSize
|
||
|
};
|
||
|
|
||
|
static const WAVEHDR wh_template = {
|
||
|
NULL, // lpData
|
||
|
0, // dwBufferLength
|
||
|
0, // dwBytesRecorded
|
||
|
0, // dwUser
|
||
|
0, // dwFlags
|
||
|
1, // dwLoops
|
||
|
NULL, // lpNext
|
||
|
0 // reserved
|
||
|
};
|
||
|
|
||
|
|
||
|
static mp3_decoder_t mp3;
|
||
|
static mp3_info_t info;
|
||
|
static unsigned char *stream_pos;
|
||
|
static int bytes_left;
|
||
|
static int byte_count;
|
||
|
static WAVEHDR wh[BUFFER_COUNT];
|
||
|
static signed short sample_buffer[MP3_MAX_SAMPLES_PER_FRAME * BUFFER_COUNT];
|
||
|
|
||
|
static HANDLE local_stdout;
|
||
|
#define out(text) WriteFile(local_stdout, (LPCVOID) text, strlen(text), NULL, NULL)
|
||
|
|
||
|
|
||
|
void CALLBACK AudioCallback(
|
||
|
HWAVEOUT hwo,
|
||
|
UINT uMsg,
|
||
|
DWORD_PTR dwInstance,
|
||
|
DWORD dwParam1,
|
||
|
DWORD dwParam2
|
||
|
) {
|
||
|
LPWAVEHDR wh = (LPWAVEHDR) dwParam1;
|
||
|
if (!wh) return;
|
||
|
if (byte_count) {
|
||
|
stream_pos += byte_count;
|
||
|
bytes_left -= byte_count;
|
||
|
waveOutUnprepareHeader(hwo, wh, sizeof(WAVEHDR));
|
||
|
waveOutPrepareHeader(hwo, wh, sizeof(WAVEHDR));
|
||
|
waveOutWrite(hwo, wh, sizeof(WAVEHDR));
|
||
|
}
|
||
|
byte_count = mp3_decode(mp3, stream_pos, bytes_left, (signed short *) wh->lpData, &info);
|
||
|
}
|
||
|
|
||
|
|
||
|
void ShowTag(const char *caption, const unsigned char *src, int max_length) {
|
||
|
static char tagbuf[32];
|
||
|
char *tagpos = tagbuf;
|
||
|
tagbuf[max_length] = '\0';
|
||
|
__asm {
|
||
|
cld
|
||
|
mov esi, src
|
||
|
mov edi, tagpos
|
||
|
mov ecx, max_length
|
||
|
rep movsb
|
||
|
}
|
||
|
if (!*tagbuf)
|
||
|
return;
|
||
|
out(caption);
|
||
|
out(tagbuf);
|
||
|
}
|
||
|
|
||
|
|
||
|
int main(void) {
|
||
|
char input_file_name[256];
|
||
|
char *inptr, *outptr = input_file_name;
|
||
|
HANDLE hFile, hMap;
|
||
|
HWAVEOUT hwo;
|
||
|
int i;
|
||
|
|
||
|
// init stdout and write banner
|
||
|
local_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||
|
out("minimp3 -- a small MPEG Audio Layer III player based on ffmpeg\n\n");
|
||
|
|
||
|
// read arguments, but skip the program name
|
||
|
for (inptr = GetCommandLine(); (*inptr) && (*inptr != ' '); ++inptr) {
|
||
|
if (*inptr == '"') // skip "quoted arguments"
|
||
|
do { ++inptr; } while (*inptr != '"');
|
||
|
}
|
||
|
// skip whitespace
|
||
|
while (*inptr == ' ') ++inptr;
|
||
|
// check for a parameter
|
||
|
if (!*inptr) {
|
||
|
// no parameter -> quit
|
||
|
out("Error: no input file specified!\n");
|
||
|
return 1;
|
||
|
} else if (*inptr == '"') {
|
||
|
// "quoted parameter"
|
||
|
++inptr;
|
||
|
while (*inptr != '"')
|
||
|
*outptr++ = *inptr++;
|
||
|
} else {
|
||
|
// unquoted parameter
|
||
|
do {
|
||
|
*outptr++ = *inptr++;
|
||
|
} while(*inptr);
|
||
|
}
|
||
|
*outptr = '\0';
|
||
|
|
||
|
// open and mmap() the file
|
||
|
hFile = CreateFile(input_file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||
|
bytes_left = GetFileSize(hFile, NULL) - 128;
|
||
|
hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||
|
stream_pos = (unsigned char*) MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
|
||
|
|
||
|
// check if the result is valid
|
||
|
if (!stream_pos) {
|
||
|
out("Error: cannot open `");
|
||
|
out(input_file_name);
|
||
|
out("'!\n");
|
||
|
return 1;
|
||
|
} else {
|
||
|
out("Now Playing: ");
|
||
|
out(input_file_name);
|
||
|
}
|
||
|
|
||
|
// check for a ID3 tag
|
||
|
inptr = stream_pos + bytes_left;
|
||
|
if (((*(unsigned long *)inptr) & 0xFFFFFF) == 0x474154) {
|
||
|
ShowTag("\nTitle: ", inptr + 3, 30);
|
||
|
ShowTag("\nArtist: ", inptr + 33, 30);
|
||
|
ShowTag("\nAlbum: ", inptr + 63, 30);
|
||
|
ShowTag("\nYear: ", inptr + 93, 4);
|
||
|
ShowTag("\nComment: ", inptr + 97, 30);
|
||
|
}
|
||
|
|
||
|
// set up minimp3 and decode the first frame
|
||
|
mp3 = mp3_create();
|
||
|
byte_count = mp3_decode(mp3, stream_pos, bytes_left, sample_buffer, &info);
|
||
|
if (!byte_count) {
|
||
|
out("\nError: not a valid MP2 audio file!\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// set up wave output
|
||
|
wf.nSamplesPerSec = info.sample_rate;
|
||
|
wf.nChannels = info.channels;
|
||
|
if(waveOutOpen(&hwo, WAVE_MAPPER, &wf, (INT_PTR) AudioCallback, (INT_PTR) NULL, CALLBACK_FUNCTION)
|
||
|
!= MMSYSERR_NOERROR) {
|
||
|
out("\nError: cannot open wave output!\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// allocate buffers
|
||
|
out("\n\nPress Ctrl+C or close the console window to stop playback.\n");
|
||
|
inptr = (char*) sample_buffer;
|
||
|
for (i = 0; i < BUFFER_COUNT; ++i) {
|
||
|
wh[i] = wh_template;
|
||
|
wh[i].lpData = inptr;
|
||
|
wh[i].dwBufferLength = info.audio_bytes;
|
||
|
AudioCallback(hwo, 0, 0, (DWORD) &wh[i], 0);
|
||
|
inptr += MP3_MAX_SAMPLES_PER_FRAME * 2;
|
||
|
}
|
||
|
|
||
|
// endless loop
|
||
|
while (1) Sleep(10);
|
||
|
|
||
|
return 0;
|
||
|
}
|