wasap.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:12k
源码类别:

Windows CE

开发平台:

C/C++

  1. /*
  2.  * wasap.c - Another Slight Atari Player for Win32 systems
  3.  *
  4.  * Copyright (C) 2005-2006  Piotr Fusik
  5.  *
  6.  * This file is part of ASAP (Another Slight Atari Player),
  7.  * see http://asap.sourceforge.net
  8.  *
  9.  * ASAP is free software; you can redistribute it and/or modify it
  10.  * under the terms of the GNU General Public License as published
  11.  * by the Free Software Foundation; either version 2 of the License,
  12.  * or (at your option) any later version.
  13.  *
  14.  * ASAP is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty
  16.  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17.  * See the GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with ASAP; if not, write to the Free Software Foundation, Inc.,
  21.  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  22.  */
  23. #include "config.h"
  24. #include <windows.h>
  25. #include <shellapi.h>
  26. #include "asap.h"
  27. #include "resource.h"
  28. #define APP_TITLE        "WASAP"
  29. #define WND_CLASS_NAME   "WASAP"
  30. #define FREQUENCY        44100
  31. #define BUFFERED_BLOCKS  4096
  32. static unsigned int use_16bit = 1;
  33. static unsigned int quality = 1;
  34. static char *Util_stpcpy(char *dest, const char *src)
  35. {
  36. size_t len = strlen(src);
  37. memcpy(dest, src, len + 1);
  38. return dest + len;
  39. }
  40. static char *Util_utoa(char *dest, unsigned int x)
  41. {
  42. char tmpbuf[16];
  43. char *p = tmpbuf + 15;
  44. *p = '';
  45. do {
  46. *--p = x % 10 + '0';
  47. x /= 10;
  48. } while (x > 0);
  49. return Util_stpcpy(dest, p);
  50. }
  51. /* WaveOut ---------------------------------------------------------------- */
  52. /* double-buffering, *2 for 16-bit, *2 for stereo */
  53. static unsigned char buffer[2][BUFFERED_BLOCKS * 2 * 2];
  54. static HWAVEOUT hwo = INVALID_HANDLE_VALUE;
  55. static WAVEHDR wh[2] = {
  56. { buffer[0], 0, 0, 0, 0, 0, NULL, 0 },
  57. { buffer[1], 0, 0, 0, 0, 0, NULL, 0 },
  58. };
  59. static int playing = FALSE;
  60. static void WaveOut_Stop(void)
  61. {
  62. if (playing) {
  63. playing = FALSE;
  64. waveOutReset(hwo);
  65. }
  66. }
  67. static void WaveOut_Write(LPWAVEHDR pwh)
  68. {
  69. if (playing) {
  70. ASAP_Generate(pwh->lpData, pwh->dwBufferLength);
  71. if (waveOutWrite(hwo, pwh, sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
  72. WaveOut_Stop();
  73. }
  74. }
  75. static void CALLBACK WaveOut_Proc(HWAVEOUT hwo2, UINT uMsg, DWORD dwInstance,
  76.                                   DWORD dwParam1, DWORD dwParam2)
  77. {
  78. if (uMsg == WOM_DONE)
  79. WaveOut_Write((LPWAVEHDR) dwParam1);
  80. }
  81. static int WaveOut_Open(unsigned int frequency, unsigned int use_16bit,
  82.                         unsigned int channels)
  83. {
  84. WAVEFORMATEX wfx;
  85. wfx.wFormatTag = WAVE_FORMAT_PCM;
  86. wfx.nChannels = channels;
  87. wfx.nSamplesPerSec = frequency;
  88. wfx.nBlockAlign = channels << use_16bit;
  89. wfx.nAvgBytesPerSec = frequency * wfx.nBlockAlign;
  90. wfx.wBitsPerSample = 8 << use_16bit;
  91. wfx.cbSize = 0;
  92. if (waveOutOpen(&hwo, WAVE_MAPPER, &wfx, (DWORD) WaveOut_Proc, 0,
  93.                 CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
  94. return FALSE;
  95. wh[1].dwBufferLength = wh[0].dwBufferLength = BUFFERED_BLOCKS * wfx.nBlockAlign;
  96. if (waveOutPrepareHeader(hwo, &wh[0], sizeof(wh[0])) != MMSYSERR_NOERROR
  97.  || waveOutPrepareHeader(hwo, &wh[1], sizeof(wh[1])) != MMSYSERR_NOERROR)
  98. return FALSE;
  99. return TRUE;
  100. }
  101. static void WaveOut_Start(void)
  102. {
  103. playing = TRUE;
  104. WaveOut_Write(&wh[0]);
  105. WaveOut_Write(&wh[1]);
  106. }
  107. static void WaveOut_Close(void)
  108. {
  109. if (hwo == INVALID_HANDLE_VALUE)
  110. return;
  111. WaveOut_Stop();
  112. if (wh[0].dwFlags & WHDR_PREPARED)
  113. waveOutUnprepareHeader(hwo, &wh[0], sizeof(wh[0]));
  114. if (wh[1].dwFlags & WHDR_PREPARED)
  115. waveOutUnprepareHeader(hwo, &wh[1], sizeof(wh[1]));
  116. waveOutClose(hwo);
  117. hwo = INVALID_HANDLE_VALUE;
  118. }
  119. /* Tray ------------------------------------------------------------------- */
  120. static unsigned int songs = 0;
  121. static unsigned int cursong = 0;
  122. static char strFile[MAX_PATH] = "";
  123. #define MYWM_NOTIFYICON  (WM_APP + 1)
  124. static void Tray_Add(HWND hWnd, HICON hIcon)
  125. {
  126. NOTIFYICONDATA nid;
  127. nid.cbSize = sizeof(NOTIFYICONDATA);
  128. nid.hWnd = hWnd;
  129. nid.uID = 0;
  130. nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  131. nid.uCallbackMessage = MYWM_NOTIFYICON;
  132. nid.hIcon = hIcon;
  133. strcpy(nid.szTip, APP_TITLE);
  134. Shell_NotifyIcon(NIM_ADD, &nid);
  135. }
  136. static void Tray_Modify(HWND hWnd, HICON hIcon)
  137. {
  138. NOTIFYICONDATA nid;
  139. char *p;
  140. nid.cbSize = sizeof(NOTIFYICONDATA);
  141. nid.hWnd = hWnd;
  142. nid.uID = 0;
  143. nid.uFlags = NIF_ICON | NIF_TIP;
  144. nid.hIcon = hIcon;
  145. /* we need to be careful because szTip is only 64 characters */
  146. /* 8 */
  147. p = Util_stpcpy(nid.szTip, APP_TITLE);
  148. if (songs > 0) {
  149. const char *pb;
  150. const char *pe;
  151. for (pe = strFile; *pe != ''; pe++);
  152. for (pb = pe; pb > strFile && pb[-1] != '\' && pb[-1] != '/'; pb--);
  153. /* 2 */
  154. *p++ = ':';
  155. *p++ = ' ';
  156. /* max 33 */
  157. if (pe - pb <= 33)
  158. p = Util_stpcpy(p, pb);
  159. else {
  160. memcpy(p, pb, 30);
  161. p = Util_stpcpy(p + 30, "...");
  162. }
  163. if (songs > 1) {
  164. /* 7 */
  165. p = Util_stpcpy(p, " (song ");
  166. /* max 3 */
  167. p = Util_utoa(p, cursong + 1);
  168. /* 4 */
  169. p = Util_stpcpy(p, " of ");
  170. /* max 3 */
  171. p = Util_utoa(p, songs);
  172. /* 2 */
  173. p[0] = ')';
  174. p[1] = '';
  175. }
  176. }
  177. Shell_NotifyIcon(NIM_MODIFY, &nid);
  178. }
  179. static void Tray_Delete(HWND hWnd)
  180. {
  181. NOTIFYICONDATA nid;
  182. nid.cbSize = sizeof(NOTIFYICONDATA);
  183. nid.hWnd = hWnd;
  184. nid.uID = 0;
  185. Shell_NotifyIcon(NIM_DELETE, &nid);
  186. }
  187. /* GUI -------------------------------------------------------------------- */
  188. static HICON hStopIcon;
  189. static HICON hPlayIcon;
  190. static HMENU hTrayMenu;
  191. static HMENU hSongMenu;
  192. static HMENU hQualityMenu;
  193. static void SetSongs(unsigned int new_songs)
  194. {
  195. if (songs < new_songs) {
  196. do {
  197. char tmp_buf[16];
  198. Util_utoa(tmp_buf, songs + 1);
  199. AppendMenu(hSongMenu, MF_ENABLED | MF_STRING,
  200.            IDM_SONG1 + songs, tmp_buf);
  201. } while (++songs < new_songs);
  202. }
  203. else if (songs > new_songs) {
  204. do
  205. DeleteMenu(hSongMenu, --songs, MF_BYPOSITION);
  206. while (songs > new_songs);
  207. }
  208. }
  209. static void PlaySong(HWND hWnd, unsigned int n)
  210. {
  211. CheckMenuRadioItem(hSongMenu, 0, songs - 1, n, MF_BYPOSITION);
  212. cursong = n;
  213. ASAP_PlaySong(n);
  214. Tray_Modify(hWnd, hPlayIcon);
  215. WaveOut_Start();
  216. }
  217. static void LoadFile(HWND hWnd)
  218. {
  219. HANDLE fh;
  220. static unsigned char module[65000];
  221. DWORD module_len;
  222. fh = CreateFile(strFile, GENERIC_READ, 0, NULL, OPEN_EXISTING,
  223.                 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  224. if (fh == INVALID_HANDLE_VALUE)
  225. return;
  226. if (!ReadFile(fh, module, sizeof(module), &module_len, NULL)) {
  227. CloseHandle(fh);
  228. return;
  229. }
  230. CloseHandle(fh);
  231. WaveOut_Close();
  232. if (ASAP_Load(strFile, module, (unsigned int) module_len)) {
  233. if (!WaveOut_Open(FREQUENCY, use_16bit, ASAP_GetChannels())) {
  234. SetSongs(0);
  235. Tray_Modify(hWnd, hStopIcon);
  236. MessageBox(hWnd, "Error initalizing WaveOut", APP_TITLE,
  237.    MB_OK | MB_ICONERROR);
  238. return;
  239. }
  240. SetSongs(ASAP_GetSongs());
  241. PlaySong(hWnd, ASAP_GetDefSong());
  242. }
  243. else {
  244. SetSongs(0);
  245. Tray_Modify(hWnd, hStopIcon);
  246. MessageBox(hWnd, "Unsupported file format", APP_TITLE,
  247.            MB_OK | MB_ICONERROR);
  248. }
  249. }
  250. static int opening = FALSE;
  251. static void SelectAndLoadFile(HWND hWnd)
  252. {
  253. static OPENFILENAME ofn = {
  254. sizeof(OPENFILENAME),
  255. NULL,
  256. 0,
  257. "All supported"
  258. "*.sap;*.cmc;*.cmr;*.dmc;*.mpt;*.mpd;*.rmt;*.tmc;*.tm8;*.tm2"
  259. "Slight Atari Player (*.sap)"
  260. "*.sap"
  261. "Chaos Music Composer (*.cmc;*.cmr;*.dmc)"
  262. "*.cmc;*.cmr;*.dmc"
  263. "Music ProTracker (*.mpt;*.mpd)"
  264. "*.mpt;*.mpd"
  265. "Raster Music Tracker (*.rmt)"
  266. "*.rmt"
  267. "Theta Music Composer 1.x (*.tmc;*.tm8)"
  268. "*.tmc;*.tm8"
  269. "Theta Music Composer 2.x (*.tm2)"
  270. "*.tm2"
  271. "",
  272. NULL,
  273. 0,
  274. 1,
  275. strFile,
  276. MAX_PATH,
  277. NULL,
  278. 0,
  279. NULL,
  280. "Select Atari 8-bit music",
  281. OFN_ENABLESIZING | OFN_EXPLORER | OFN_HIDEREADONLY
  282. | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
  283. 0,
  284. 0,
  285. NULL,
  286. 0,
  287. NULL,
  288. NULL
  289. };
  290. opening = TRUE;
  291. ofn.hwndOwner = hWnd;
  292. if (GetOpenFileName(&ofn))
  293. LoadFile(hWnd);
  294. opening = FALSE;
  295. }
  296. static void SetQuality(HWND hWnd, unsigned int new_16bit, unsigned int new_quality)
  297. {
  298. int reopen = FALSE;
  299. if (songs > 0) {
  300. WaveOut_Stop();
  301. SetSongs(0);
  302. Tray_Modify(hWnd, hStopIcon);
  303. reopen = TRUE;
  304. }
  305. CheckMenuRadioItem(hQualityMenu, IDM_8BIT, IDM_16BIT,
  306. IDM_8BIT + new_16bit, MF_BYCOMMAND);
  307. CheckMenuRadioItem(hQualityMenu, IDM_QUALITY_RF, IDM_QUALITY_MB3,
  308. IDM_QUALITY_RF + new_quality, MF_BYCOMMAND);
  309. ASAP_Initialize(FREQUENCY, new_16bit, new_quality);
  310. use_16bit = new_16bit;
  311. quality = new_quality;
  312. if (reopen)
  313. LoadFile(hWnd);
  314. }
  315. static LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam,
  316.                                     LPARAM lParam)
  317. {
  318. UINT idc;
  319. POINT pt;
  320. PCOPYDATASTRUCT pcds;
  321. switch (msg) {
  322. case WM_COMMAND:
  323. if (opening)
  324. break;
  325. idc = LOWORD(wParam);
  326. switch (idc) {
  327. case IDM_OPEN:
  328. SelectAndLoadFile(hWnd);
  329. break;
  330. case IDM_STOP:
  331. WaveOut_Stop();
  332. Tray_Modify(hWnd, hStopIcon);
  333. break;
  334. case IDM_ABOUT:
  335. MessageBox(hWnd,
  336. ASAP_CREDITS
  337. "WASAP icons (C) 2005 Lukasz Sychowicznn"
  338. ASAP_COPYRIGHT,
  339. APP_TITLE " " ASAP_VERSION,
  340. MB_OK | MB_ICONINFORMATION);
  341. break;
  342. case IDM_EXIT:
  343. PostQuitMessage(0);
  344. break;
  345. default:
  346. if (idc >= IDM_SONG1 && idc < IDM_SONG1 + songs) {
  347. WaveOut_Stop();
  348. PlaySong(hWnd, idc - IDM_SONG1);
  349. }
  350. else if (idc >= IDM_QUALITY_RF && idc <= IDM_QUALITY_MB3)
  351. SetQuality(hWnd, use_16bit, idc - IDM_QUALITY_RF);
  352. else if (idc >= IDM_8BIT && idc <= IDM_16BIT)
  353. SetQuality(hWnd, idc - IDM_8BIT, quality);
  354. break;
  355. }
  356. break;
  357. case WM_DESTROY:
  358. PostQuitMessage(0);
  359. break;
  360. case MYWM_NOTIFYICON:
  361. if (opening) {
  362. SetForegroundWindow(GetLastActivePopup(hWnd));
  363. break;
  364. }
  365. switch (lParam) {
  366. case WM_LBUTTONDOWN:
  367. SelectAndLoadFile(hWnd);
  368. break;
  369. case WM_RBUTTONDOWN:
  370. GetCursorPos(&pt);
  371. SetForegroundWindow(hWnd);
  372. TrackPopupMenu(hTrayMenu,
  373. TPM_RIGHTALIGN | TPM_BOTTOMALIGN | TPM_RIGHTBUTTON,
  374. pt.x, pt.y, 0, hWnd, NULL);
  375. PostMessage(hWnd, WM_NULL, 0, 0);
  376. break;
  377. default:
  378. break;
  379. }
  380. break;
  381. case WM_COPYDATA:
  382. pcds = (PCOPYDATASTRUCT) lParam;
  383. if (pcds->dwData == 'O' && pcds->cbData <= sizeof(strFile)) {
  384. memcpy(strFile, pcds->lpData, pcds->cbData);
  385. LoadFile(hWnd);
  386. }
  387. break;
  388. default:
  389. return DefWindowProc(hWnd, msg, wParam, lParam);
  390. }
  391. return 0;
  392. }
  393. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  394.                    LPSTR lpCmdLine, int nCmdShow)
  395. {
  396. char *pb;
  397. char *pe;
  398. WNDCLASS wc;
  399. HWND hWnd;
  400. HMENU hMainMenu;
  401. MSG msg;
  402. for (pb = lpCmdLine; *pb == ' ' || *pb == 't'; pb++);
  403. for (pe = pb; *pe != ''; pe++);
  404. while (--pe > pb && (*pe == ' ' || *pe == 't'));
  405. /* Now pb and pe point at respectively the first and last
  406.    non-blank character in lpCmdLine. If pb > pe then the command line
  407.    is blank. */
  408. if (*pb == '"' && *pe == '"')
  409. pb++;
  410. else
  411. pe++;
  412. *pe = '';
  413. /* Now pb contains the filename, if any, specified on the command line. */
  414. hWnd = FindWindow(WND_CLASS_NAME, NULL);
  415. if (hWnd != NULL) {
  416. /* as instance of WASAP is already running */
  417. if (*pb != '') {
  418. /* pass the filename */
  419. COPYDATASTRUCT cds = { 'O', (DWORD) (pe + 1 - pb), pb };
  420. SendMessage(hWnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds);
  421. }
  422. else {
  423. /* bring the open dialog to top */
  424. HWND hChild = GetLastActivePopup(hWnd);
  425. if (hChild != hWnd)
  426. SetForegroundWindow(hChild);
  427. }
  428. return 0;
  429. }
  430. wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
  431. wc.lpfnWndProc = MainWndProc;
  432. wc.cbClsExtra = 0;
  433. wc.cbWndExtra = 0;
  434. wc.hInstance = hInstance;
  435. wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APP));
  436. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  437. wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  438. wc.lpszMenuName = NULL;
  439. wc.lpszClassName = WND_CLASS_NAME;
  440. RegisterClass(&wc);
  441. hWnd = CreateWindow(WND_CLASS_NAME,
  442. APP_TITLE,
  443. WS_OVERLAPPEDWINDOW,
  444. CW_USEDEFAULT,
  445. CW_USEDEFAULT,
  446. CW_USEDEFAULT,
  447. CW_USEDEFAULT,
  448. NULL,
  449. NULL,
  450. hInstance,
  451. NULL
  452. );
  453. hStopIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_STOP));
  454. hPlayIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PLAY));
  455. hMainMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_TRAYMENU));
  456. hTrayMenu = GetSubMenu(hMainMenu, 0);
  457. hSongMenu = CreatePopupMenu();
  458. InsertMenu(hTrayMenu, 1, MF_BYPOSITION | MF_ENABLED | MF_STRING | MF_POPUP,
  459.            (UINT_PTR) hSongMenu, "So&ng");
  460. hQualityMenu = GetSubMenu(hTrayMenu, 3);
  461. SetMenuDefaultItem(hTrayMenu, 0, TRUE);
  462. Tray_Add(hWnd, hStopIcon);
  463. SetQuality(hWnd, use_16bit, quality);
  464. if (*pb != '') {
  465. memcpy(strFile, pb, pe + 1 - pb);
  466. LoadFile(hWnd);
  467. }
  468. else
  469. SelectAndLoadFile(hWnd);
  470. while (GetMessage(&msg, NULL, 0, 0)) {
  471. TranslateMessage(&msg);
  472. DispatchMessage(&msg);
  473. }
  474. WaveOut_Close();
  475. Tray_Delete(hWnd);
  476. DestroyMenu(hMainMenu);
  477. return 0;
  478. }