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

Windows CE

开发平台:

C/C++

  1. /*****************************************************************************  *  * This program is free software ; you can redistribute it and/or modify  * it under the terms of the GNU General Public License as published by  * the Free Software Foundation; either version 2 of the License, or  * (at your option) any later version.  *  * This program is distributed in the hope that it will be useful,  * but WITHOUT ANY WARRANTY; without even the implied warranty of  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  * GNU General Public License for more details.  *  * You should have received a copy of the GNU General Public License  * along with this program; if not, write to the Free Software  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA  *  * $Id: waveout_palmos.c 623 2006-02-01 13:19:15Z picard $  *  * The Core Pocket Media Player  * Copyright (c) 2004-2005 Gabor Kovacs  *  ****************************************************************************/ #include "../common.h" #if defined(TARGET_PALMOS)
  2. #define DRVBUFFER 4096
  3. #define BUFFER_MIN 4*DRVBUFFER
  4. #define BUFFER_MUSIC 65536*8
  5. #define BUFFER_VIDEO 65536
  6. #define VOLLIMIT (16384-64)
  7. #include "pace.h"
  8. typedef struct waveout_palm
  9. {
  10. waveout_base Base;
  11. SndStreamRef Stream;
  12. sysregs SysRegs;
  13. void* PCMCopy;
  14. int CopySpeed;
  15. bool_t Mute;
  16. int Volume;
  17. int PreAmp;
  18. int Pan;
  19. bool_t Play;
  20. bool_t Started;
  21. fraction Speed;
  22. fraction SpeedTime;
  23. buffer Buffer;
  24. bool_t BufferMode;
  25. int VolumeRamp;
  26. int BytePerSample; // output bytes per sample
  27. int BytePerSec; // output bytes per seconds (before speed adjustment)
  28. int SpeedBytePerSec; // speed adjusted BytePerSec
  29. int Ratio; //input to output bytepersec (8.8 fixed point)
  30. int Skip;
  31. int DrvBufferSize;
  32. tick_t DrvBufferDelay;
  33. tick_t BufferTick;
  34. tick_t Tick;
  35. int TimeRef;
  36. int BenchSpeed;
  37. int BenchLeft;
  38. bool_t AlwaysClose;
  39. bool_t Force16Bits;
  40. int Vol;
  41. Boolean Native;
  42. m68kcallback CallBack;
  43. } waveout_palm;
  44. #define WAVEOUT(p) ((waveout_palm*)((char*)(p)-OFS(waveout_palm,Base.Timer)))
  45. static void ManualSleep(int MSec)
  46. {
  47. int t0 = GetTimeTick();
  48. int Wait = (GetTimeFreq()*MSec)/1024;
  49. if (Wait==0) Wait=1;
  50. while (GetTimeTick()-t0<Wait);
  51. }
  52. static int Stop(waveout_palm* p)
  53. {
  54. if (p->Started)
  55. {
  56. p->Started = 0;
  57. SndStreamStop(p->Stream);
  58. ManualSleep(50); // try to make sure callback exited
  59. if (p->AlwaysClose)
  60. {
  61. SndStreamDelete(p->Stream);
  62. p->Stream = 0;
  63. }
  64. p->DrvBufferSize = 0;
  65. p->DrvBufferDelay = 0;
  66. }
  67. return ERR_NONE;
  68. }
  69. static int CreateStream(waveout_palm* p);
  70. static void Start(waveout_palm* p,tick_t CurrTime)
  71. {
  72. if (p->Play && !p->Started && p->Buffer.WritePos != p->Buffer.ReadPos &&
  73. (CurrTime<0 || p->BufferTick <= CurrTime+SHOWAHEAD) &&
  74. (p->Stream || CreateStream(p)==ERR_NONE))
  75. {
  76. p->Started = 1;
  77. SndStreamStart(p->Stream);
  78. }
  79. }
  80. static int UpdateBufferMode(waveout_palm* p)
  81. {
  82. int Size;
  83. if (p->Started)
  84. return ERR_NONE;
  85. BufferPack(&p->Buffer,0);
  86. Size = p->BufferMode ? BUFFER_VIDEO : BUFFER_MUSIC;
  87. if (Context()->LowMemory)
  88. Size >>= 1;
  89. if (Size < BUFFER_MIN)
  90. Size = BUFFER_MIN;
  91. Size = ALIGN16(Size);
  92. DisableOutOfMemory();
  93. for (;Size >= BUFFER_MIN;Size >>= 1)
  94. if (BufferAlloc(&p->Buffer,Size,1))
  95. {
  96. EnableOutOfMemory();
  97. if (p->Buffer.WritePos >= p->Buffer.Allocated)
  98. p->Buffer.WritePos = 0;
  99. return ERR_NONE;
  100. }
  101. EnableOutOfMemory();
  102. ShowOutOfMemory();
  103. return ERR_OUT_OF_MEMORY;
  104. }
  105. static Err Callback(waveout_palm* p,SndStreamRef Stream,void *Buffer,uint32_t Frames)
  106. {
  107. // as a general rule we don't call any OS callbacks here, because
  108. // we only have one emulstate structure and if both threads
  109. // call an m68k syscall this could mean problems...
  110. constplanes SrcPlanes;
  111. planes DstPlanes;
  112. int SrcLength,DstLength;
  113. int WritePos,ReadPos,Length,Speed;
  114. LoadSysRegs(&p->SysRegs);
  115. Length = Frames * p->BytePerSample;
  116. DstPlanes[0] = Buffer;
  117. if (p->Started)
  118. {
  119. WritePos = p->Buffer.WritePos;
  120. ReadPos = p->Buffer.ReadPos;
  121. if (p->DrvBufferSize != Length)
  122. {
  123. //assuming double buffering
  124. p->DrvBufferSize = Length;
  125. p->DrvBufferDelay = Scale(2*Length,TICKSPERSEC,p->SpeedBytePerSec); 
  126. }
  127. Speed = p->CopySpeed;
  128. if (Speed <= 0) 
  129. {
  130. /* int Middle = p->Buffer.Allocated >> 1;
  131. int Left = ReadPos - WritePos;
  132. if (Left<0)
  133. Left += p->Buffer.Allocated;
  134. Speed = p->BenchSpeed;
  135. if (Left > Middle && p->BenchLeft < Left)
  136. {
  137. Speed -= Left - p->BenchLeft;
  138. if (Speed < SPEED_ONE/8)
  139. Speed = SPEED_ONE/8;
  140. }
  141. if (Left < Middle && p->BenchLeft > Left)
  142. Speed -= Left - p->BenchLeft;
  143. p->BenchSpeed = Speed;
  144. p->BenchLeft = Left;
  145. */
  146. Speed = SPEED_ONE;
  147. }
  148. while (Length>0)
  149. {
  150. if (WritePos < ReadPos)
  151. SrcLength = p->Buffer.Allocated - ReadPos;
  152. else
  153. SrcLength = WritePos - ReadPos;
  154. SrcPlanes[0] = p->Buffer.Data + ReadPos;
  155. DstLength = Length;
  156. PCMConvert(p->PCMCopy,DstPlanes,SrcPlanes,&DstLength,&SrcLength,Speed,256);
  157. DstPlanes[0] = (uint8_t*)DstPlanes[0] + DstLength;
  158. Length -= DstLength;
  159. ReadPos += SrcLength;
  160. if (ReadPos == p->Buffer.Allocated)
  161. ReadPos = 0;
  162. if (!DstLength)
  163. break;
  164. }
  165. p->Buffer.ReadPos = ReadPos;
  166. }
  167. if (Length)
  168. memset(DstPlanes[0],(p->Base.Output.Format.Audio.Flags & PCM_UNSIGNED)?0x80:0x00,Length);
  169. return errNone;
  170. }
  171. DLLEXPORT unsigned long WaveOutCallBack(const void *emulStateP, void *userData68KP, Call68KFuncType *call68KFuncP)
  172. {
  173. UInt32 Param[4];
  174. memcpy(Param,userData68KP,16);
  175. return Callback((waveout_palm*)SWAP32(Param[0]),(SndStreamRef)SWAP32(Param[1]),
  176. (void*)SWAP32(Param[2]),SWAP32(Param[3]));
  177. }
  178. static int Process(waveout_palm* p,const packet* Packet,const flowstate* State)
  179. {
  180. constplanes SrcPlanes;
  181. planes DstPlanes;
  182. int Length,SrcLength,DstLength,Left,ReadPos,WritePos;
  183. ReadPos = p->Buffer.ReadPos;
  184. WritePos = p->Buffer.WritePos;
  185. if (!Packet)
  186. {
  187. if (State->DropLevel)
  188. ++p->Base.Dropped;
  189. return (!p->Started || !p->Speed.Num || WritePos==ReadPos) ? ERR_NONE : ERR_BUFFER_FULL;
  190. }
  191. DstLength = (Packet->Length * p->Ratio + 255) >> 8; // it may give little larger as needed length
  192. if (DstLength > p->Buffer.Allocated - DRVBUFFER*2)
  193. {
  194. ++p->Base.Dropped;
  195. return ERR_NONE; // drop large packets
  196. }
  197. // avoid filling the buffer full (it would mean buffer is empty)
  198. ReadPos -= p->BytePerSample;
  199. if (ReadPos < 0)
  200. ReadPos += p->Buffer.Allocated;
  201. // check if there is enough free space in buffer
  202. Left = ReadPos - WritePos;
  203. if (Left<0)
  204. Left += p->Buffer.Allocated;
  205. if (DstLength > Left)
  206. {
  207. if (!p->Started)
  208. Start(p,State->CurrTime);
  209. if (p->Speed.Num)
  210. return ERR_BUFFER_FULL;
  211. // in benchmark mode we need the package to 
  212. // be processed to measure real performance
  213. WritePos = ReadPos - DstLength;
  214. WritePos &= ~3; // align to dword (DstLength is just an approx)
  215. if (WritePos<0)
  216. WritePos += p->Buffer.Allocated;
  217. Left = ReadPos - WritePos;
  218. if (Left<0)
  219. Left += p->Buffer.Allocated;
  220. }
  221. // process packet
  222. SrcPlanes[0] = Packet->Data[0];
  223. SrcPlanes[1] = Packet->Data[1];
  224. Length = Packet->Length;
  225. p->Base.Total += Length;
  226. if (Packet->RefTime >= 0)
  227. {
  228. int Diff = p->Buffer.Allocated - Left; // bytes already in the buffer (with 100% speed)
  229. p->BufferTick = Packet->RefTime - Scale(Diff,TICKSPERSEC,p->BytePerSec) - p->DrvBufferDelay;
  230. if (p->BufferTick < 0)
  231. p->BufferTick = 0;
  232. if (p->Started)
  233. {
  234. // adjust timer if it's already running
  235. int Time = GetTimeTick();
  236. tick_t Tick = Scale(Time-p->TimeRef,p->SpeedTime.Num,p->SpeedTime.Den);
  237. tick_t Old = p->Tick + Tick;
  238. // if difference is little then just adjust (because GetTimeTick() is more linear)
  239. if (abs(Old - p->BufferTick) < TICKSPERSEC/2)
  240. p->BufferTick = Old + ((p->BufferTick - Old) >> 2);
  241. p->Tick = p->BufferTick;
  242. p->TimeRef = Time;
  243. }
  244. }
  245. if (p->Skip)
  246. {
  247. SrcLength = min(p->Skip,Length);
  248. SrcPlanes[0] = (uint8_t*)SrcPlanes[0] + SrcLength;
  249. SrcPlanes[1] = (uint8_t*)SrcPlanes[1] + SrcLength;
  250. Length -= SrcLength;
  251. p->Skip -= SrcLength;
  252. }
  253. while (Length>0)
  254. {
  255. if (ReadPos < WritePos)
  256. DstLength = p->Buffer.Allocated - WritePos;
  257. else
  258. DstLength = ReadPos - WritePos;
  259. DstPlanes[0] = p->Buffer.Data + WritePos;
  260. SrcLength = Length;
  261. PCMConvert(p->Base.PCM,DstPlanes,SrcPlanes,&DstLength,&SrcLength,SPEED_ONE,p->Vol/4); //volume needed only for lifedrive fix
  262. if (p->VolumeRamp < RAMPLIMIT)
  263. p->VolumeRamp = VolumeRamp(p->VolumeRamp,DstPlanes[0],DstLength,&p->Base.Output.Format.Audio);
  264. SrcPlanes[0] = (uint8_t*)SrcPlanes[0] + SrcLength;
  265. SrcPlanes[1] = (uint8_t*)SrcPlanes[1] + SrcLength;
  266. Length -= SrcLength;
  267. WritePos += DstLength;
  268. if (WritePos == p->Buffer.Allocated)
  269. WritePos = 0;
  270. if (!SrcLength) // unaligned input (not supported)
  271. break;
  272. }
  273. p->Buffer.WritePos = WritePos;
  274. if (Length>0 && p->Base.Input.Format.Audio.BlockAlign>0)
  275. p->Skip = p->Base.Input.Format.Audio.BlockAlign - Length % p->Base.Input.Format.Audio.BlockAlign;
  276. if (!p->Started)
  277. Start(p,State->CurrTime);
  278. return ERR_NONE;
  279. }
  280. static int Flush(waveout_palm* p)
  281. {
  282. Stop(p);
  283. p->Skip = 0;
  284. p->VolumeRamp = 0;
  285. p->BufferTick = -1;
  286. p->Buffer.ReadPos = p->Buffer.WritePos = 0;
  287. p->BenchSpeed = SPEED_ONE;
  288. p->BenchLeft = 0;
  289. return ERR_NONE;
  290. }
  291. static int Done(waveout_palm* p)
  292. {
  293. Flush(p);
  294. if (p->Stream)
  295. {
  296. // Tungsten T1 seems to still use one or two callbacks after stopping
  297. SndStreamSetVolume(p->Stream,0);
  298. ManualSleep(100);
  299. SndStreamDelete(p->Stream);
  300. p->Stream = 0;
  301. }
  302. BufferClear(&p->Buffer);
  303. PCMRelease(p->PCMCopy);
  304. p->PCMCopy = NULL;
  305. PCMRelease(p->Base.PCM);
  306. p->Base.PCM = NULL;
  307. return ERR_NONE;
  308. }
  309. static const int32_t VolDb[201] = { //pow(10,(50+N)/49.828)
  310. 10,10,11,11,12,12,13,13,14,15,
  311. 16,16,17,18,19,20,21,22,23,24,
  312. 25,26,27,29,30,32,33,35,36,38,
  313. 40,42,44,46,48,50,53,55,58,61,
  314. 64,67,70,73,76,80,84,88,92,97,
  315. 101,106,111,116,122,128,134,140,147,154,
  316. 161,168,176,185,194,203,212,222,233,244,
  317. 256,268,280,294,308,322,337,353,370,388,
  318. 406,425,445,466,488,512,536,561,588,616,
  319. 645,675,707,741,776,812,851,891,933,977,
  320. 1024,1072,1123,1176,1232,1290,1351,1415,1482,1552,
  321. 1625,1702,1783,1867,1955,2048,2145,2246,2352,2464,
  322. 2580,2702,2830,2964,3104,3251,3405,3566,3734,3911,
  323. 4096,4290,4493,4705,4928,5161,5405,5661,5928,6209,
  324. 6503,6810,7132,7470,7823,8193,8580,8986,9411,9856,
  325. 10323,10811,11322,11858,12418,13006,13621,14265,14940,15646,
  326. 16386,17161,17973,18823,19713,20646,21622,22645,23716,24838,
  327. 26012,27243,28531,29881,31294,32774,34324,35947,37647,39428,
  328. 41293,43246,45291,47433,49676,52026,54486,57063,59762,62589,
  329. 65549,68649,71896,75296,78857,82587,86493,90584,94868,99355,
  330. 104054};
  331. static int UpdateVolume(waveout_palm* p)
  332. {
  333. if (p->Stream)
  334. {
  335. if (p->Mute || p->Volume<0)
  336. p->Vol = 0;
  337. else
  338. {
  339. int PreAmp = p->PreAmp+100;
  340. if (PreAmp<0) PreAmp=0;
  341. if (PreAmp>200) PreAmp=200;
  342. p->Vol = Scale(p->Volume,VolDb[PreAmp],100);
  343. if (p->Vol > VOLLIMIT)
  344. p->Vol = VOLLIMIT;
  345. }
  346. SndStreamSetVolume(p->Stream,p->Vol);
  347. }
  348. return ERR_NONE;
  349. }
  350. static int UpdatePan(waveout_palm* p)
  351. {
  352. if (p->Stream)
  353. SndStreamSetPan(p->Stream,(p->Pan*1024)/100);
  354. return ERR_NONE;
  355. }
  356. static NOINLINE int UpdateSpeed(waveout_palm* p)
  357. {
  358. p->SpeedTime = p->Speed;
  359. p->SpeedTime.Num *= TICKSPERSEC;
  360. p->SpeedTime.Den *= GetTimeFreq();
  361. if (!p->Speed.Num)
  362. p->CopySpeed = 0; //benchmark mode
  363. else
  364. p->CopySpeed = Scale(SPEED_ONE,p->Speed.Num,p->Speed.Den);
  365. p->SpeedBytePerSec = Scale(p->BytePerSec,p->Speed.Den,p->Speed.Num);
  366. p->DrvBufferSize = 0;
  367. p->DrvBufferDelay = 0;
  368. return ERR_NONE;
  369. }
  370. static int CreateStream(waveout_palm* p)
  371. {
  372. SndSampleType Type;
  373. SndStreamWidth Width;
  374. #if defined(_M_IX86)
  375. // this mess is all about avoiding simulator error message (no clue why the orginal pointer is invalid)
  376. static uint8_t CallbackJmp[] = {0xB8,0,0,0,0,0xFF,0xE0};
  377. SndStreamBufferCallback CallbackPtr = (SndStreamBufferCallback)CallbackJmp;
  378. *(SndStreamBufferCallback*)(CallbackJmp+1) = (SndStreamBufferCallback)Callback;
  379. if (!p->Native)
  380. CallbackPtr = (SndStreamBufferCallback)m68kCallBack(p->CallBack,(NativeFuncType*)T("tcpmp.dllWaveOutCallBack"));
  381. #else
  382. SndStreamBufferCallback CallbackPtr = (SndStreamBufferCallback)Callback;
  383. if (!p->Native)
  384. CallbackPtr = (SndStreamBufferCallback)m68kCallBack(p->CallBack,WaveOutCallBack);
  385. #endif
  386. if (p->Base.Output.Format.Audio.Bits==16)
  387. {
  388. if (p->Base.Output.Format.Audio.Flags & PCM_SWAPEDBYTES)
  389. Type = sndInt16Big;
  390. else
  391. Type = sndInt16Little;
  392. }
  393. else
  394. if (p->Base.Output.Format.Audio.Bits==8)
  395. {
  396. if (p->Base.Output.Format.Audio.Flags & PCM_UNSIGNED)
  397. Type = sndUInt8;
  398. else
  399. Type = sndInt8;
  400. }
  401. else
  402. return ERR_NOT_SUPPORTED;
  403. switch (p->Base.Output.Format.Audio.Channels)
  404. {
  405. case 1: Width = sndMono; break;
  406. case 2: Width = sndStereo; break;
  407. default: 
  408. return ERR_NOT_SUPPORTED;
  409. }
  410. SaveSysRegs(&p->SysRegs);
  411. if (SndStreamCreate(&p->Stream,sndOutput,p->Base.Output.Format.Audio.SampleRate,Type,
  412. Width,CallbackPtr,p,DRVBUFFER,p->Native) != errNone)
  413. return ERR_DEVICE_ERROR;
  414. UpdateVolume(p);
  415. UpdatePan(p);
  416. return ERR_NONE;
  417. }
  418. static void Force16Bits(waveout_palm* p)
  419. {
  420. if (p->Base.Output.Format.Audio.Bits<16)
  421. {
  422. p->Base.Output.Format.Audio.Flags &= ~PCM_UNSIGNED;
  423. p->Base.Output.Format.Audio.Bits = 16;
  424. p->Base.Output.Format.Audio.FracBits = 15;
  425. }
  426. }
  427. static int Init(waveout_palm* p)
  428. {
  429. int Model = QueryPlatform(PLATFORM_MODEL);
  430. int InputRate;
  431. int Result;
  432. if (p->Force16Bits)
  433. Force16Bits(p); // NX80v with MCA2 doesn't like 8bit output?
  434. if (Model == MODEL_LIFEDRIVE)
  435. p->Base.Output.Format.Audio.Flags |= PCM_LIFEDRIVE_FIX;
  436. if (Model == MODEL_TUNGSTEN_T || Model == MODEL_TUNGSTEN_T2 || Model == MODEL_TUNGSTEN_T3)
  437. {
  438. if (Model != MODEL_TUNGSTEN_T3 && p->Base.Output.Format.Audio.SampleRate > 44100) //48000hz unstable on T|T and T2
  439. p->Base.Output.Format.Audio.SampleRate = 44100;
  440. // on my T3 (updated ROM) 24000hz crashes almost always
  441. if (p->Base.Output.Format.Audio.SampleRate > 22050 && p->Base.Output.Format.Audio.SampleRate < 32000)
  442. p->Base.Output.Format.Audio.SampleRate = 32000;
  443. if (p->Base.Output.Format.Audio.SampleRate > 16000 && p->Base.Output.Format.Audio.SampleRate < 22050)
  444. p->Base.Output.Format.Audio.SampleRate = 22050;
  445. if (p->Base.Output.Format.Audio.SampleRate > 11025 && p->Base.Output.Format.Audio.SampleRate < 16000)
  446. p->Base.Output.Format.Audio.SampleRate = 16000;
  447. }
  448. if (Model == MODEL_ZODIAC)
  449. {
  450. // it seems Zodiac doesn't support 48000Hz
  451. if (p->Base.Output.Format.Audio.SampleRate > 44100)
  452. p->Base.Output.Format.Audio.SampleRate = 44100;
  453. }
  454. // in general for digital camera movies:
  455. if (p->Base.Output.Format.Audio.SampleRate > 8000 && p->Base.Output.Format.Audio.SampleRate < 11025)
  456. {
  457. p->Base.Output.Format.Audio.SampleRate = 11025;
  458. Force16Bits(p);
  459. }
  460. if (p->Base.Output.Format.Audio.SampleRate <= 8000)
  461. {
  462. p->Base.Output.Format.Audio.SampleRate = 8000;
  463. Force16Bits(p);
  464. }
  465. InputRate = (p->Base.Input.Format.Audio.Bits/8)*p->Base.Input.Format.Audio.SampleRate;
  466. if (!(p->Base.Input.Format.Audio.Flags & PCM_PLANES))
  467. InputRate *= p->Base.Input.Format.Audio.Channels;
  468. if (!InputRate)
  469. return ERR_NOT_SUPPORTED;
  470. Result = CreateStream(p);
  471. if (Result != ERR_NONE)
  472. return Result;
  473. p->BufferMode = 1;
  474. p->TimeRef = GetTimeTick();
  475. p->BytePerSample = (p->Base.Output.Format.Audio.Bits * p->Base.Output.Format.Audio.Channels)/8;
  476. p->BytePerSec = p->Base.Output.Format.Audio.SampleRate * p->BytePerSample;
  477. p->Ratio = (256 * p->BytePerSec + InputRate - 1) / InputRate;
  478. WaveOutPCM(&p->Base);
  479. p->PCMCopy = PCMCreate(&p->Base.Output.Format.Audio,&p->Base.Output.Format.Audio,0,0);
  480. if (!p->PCMCopy || !p->Base.PCM)
  481. return ERR_OUT_OF_MEMORY;
  482. if (UpdateBufferMode(p) != ERR_NONE)
  483. return ERR_OUT_OF_MEMORY;
  484. UpdateSpeed(p);
  485. return ERR_NONE;
  486. }
  487. static int UpdatePlay(waveout_palm* p)
  488. {
  489. if (p->Play)
  490. {
  491. p->TimeRef = GetTimeTick();
  492. Start(p,p->Tick);
  493. }
  494. else
  495. {
  496. //tick_t Adjust = p->DrvBufferDelay; can be too big jump into the future, which is disturbing at pause
  497. int Tick = GetTimeTick();
  498. Stop(p);
  499. p->Tick += Scale(Tick-p->TimeRef,p->SpeedTime.Num,p->SpeedTime.Den);// + Adjust;
  500. }
  501. return ERR_NONE;
  502. }
  503. static int TimerGet(void* pt, int No, void* Data, int Size)
  504. {
  505. waveout_palm* p = WAVEOUT(pt);
  506. int Result = ERR_INVALID_PARAM;
  507. switch (No)
  508. {
  509. case TIMER_PLAY: GETVALUE(p->Play,bool_t); break;
  510. case TIMER_SPEED: GETVALUE(p->Speed,fraction); break;
  511. case TIMER_TIME:
  512. assert(Size == sizeof(tick_t));
  513. if (p->Speed.Num==0)
  514. *(tick_t*)Data = TIME_BENCH;
  515. else
  516. if (p->Play)
  517. *(tick_t*)Data = p->Tick + Scale(GetTimeTick()-p->TimeRef,p->SpeedTime.Num,p->SpeedTime.Den);
  518. else
  519. *(tick_t*)Data = p->Tick;
  520. Result = ERR_NONE;
  521. break;
  522. }
  523. return Result;
  524. }
  525. static int TimerSet(void* pt, int No, const void* Data, int Size)
  526. {
  527. waveout_palm* p = WAVEOUT(pt);
  528. int Result = ERR_INVALID_PARAM;
  529. switch (No)
  530. {
  531. case TIMER_PLAY: SETVALUECMP(p->Play,bool_t,UpdatePlay(p),EqBool); break;
  532. case TIMER_SPEED: SETVALUECMP(p->Speed,fraction,UpdateSpeed(p),EqFrac); break;
  533. case TIMER_TIME:
  534. assert(Size == sizeof(tick_t));
  535. p->Tick = *(tick_t*)Data;
  536. p->TimeRef = GetTimeTick();
  537. Result = ERR_NONE;
  538. break;
  539. }
  540. return Result;
  541. }
  542. static int Get(waveout_palm* p, int No, void* Data, int Size)
  543. {
  544. int Result = WaveOutBaseGet(&p->Base,No,Data,Size);
  545. switch (No)
  546. {
  547. case AOUT_VOLUME: GETVALUE(p->Volume,int); break;
  548. case AOUT_MUTE: GETVALUE(p->Mute,bool_t); break;
  549. case AOUT_PREAMP: GETVALUE(p->PreAmp,int); break;
  550. case AOUT_PAN: GETVALUE(p->Pan,int); break;
  551. case AOUT_MODE: GETVALUE(p->BufferMode,bool_t); break;
  552. }
  553. return Result;
  554. }
  555. static int Set(waveout_palm* p, int No, const void* Data, int Size) { int Result = WaveOutBaseSet(&p->Base,No,Data,Size); switch (No) { case AOUT_VOLUME: SETVALUECMP(p->Volume,int,UpdateVolume(p),EqInt); break; case AOUT_MUTE: SETVALUECMP(p->Mute,bool_t,UpdateVolume(p),EqBool); break; 
  556. case AOUT_PREAMP: SETVALUECMP(p->PreAmp,int,UpdateVolume(p),EqInt); break;
  557. case AOUT_PAN: SETVALUECMP(p->Pan,int,UpdatePan(p),EqInt); break;
  558. case AOUT_MODE: SETVALUECMP(p->BufferMode,bool_t,UpdateBufferMode(p),EqBool); break;
  559. case FLOW_FLUSH:
  560. Result = Flush(p);
  561. break;
  562. } return Result; }
  563. static int Create(waveout_palm* p)
  564. {
  565. int Model = QueryPlatform(PLATFORM_MODEL);
  566. UInt32 CompanyID;
  567. UInt32 Version;
  568. if (Model!=MODEL_TUNGSTEN_T && (FtrGet(sysFileCSoundMgr, sndFtrIDVersion, &Version)!=errNone || Version<100))
  569. return ERR_NOT_SUPPORTED;
  570. p->Base.Init = (nodefunc)Init;
  571. p->Base.Done = (nodefunc)Done;
  572. p->Base.Process = (packetprocess)Process;
  573. p->Base.Node.Get = (nodeget)Get;
  574. p->Base.Node.Set = (nodeset)Set;
  575. p->Base.Timer.Class = TIMER_CLASS;
  576. p->Base.Timer.Enum = TimerEnum;
  577. p->Base.Timer.Get = TimerGet;
  578. p->Base.Timer.Set = TimerSet;
  579. p->Base.Quality = 2;
  580. p->Speed.Num = 1;
  581. p->Speed.Den = 1;
  582. FtrGet(sysFtrCreator, sysFtrNumOEMCompanyID, &CompanyID);
  583. FtrGet(sysFtrCreator, sysFtrNumROMVersion, &Version);
  584. // I think MCA2 doesn't like more stop and start sequences. Stream has to deleted and recreated
  585. p->AlwaysClose = CompanyID == 'sony' && sysGetROMVerMajor(Version)==5 && sysGetROMVerMinor(Version)<2;
  586. p->Force16Bits = sysGetROMVerMajor(Version)==5 && sysGetROMVerMinor(Version)<2;
  587. p->Native = 1;
  588. if (Model==MODEL_QDA700)
  589. p->Native = 0; // crashes with ARM callback(?)
  590. return ERR_NONE;
  591. }
  592. static const nodedef WaveOut =
  593. {
  594. sizeof(waveout_palm)|CF_GLOBAL,
  595. WAVEOUT_ID,
  596. AOUT_CLASS,
  597. PRI_DEFAULT,
  598. (nodecreate)Create,
  599. };
  600. void WaveOut_Init() { NodeRegisterClass(&WaveOut);
  601. } void WaveOut_Done() { NodeUnRegisterClass(WAVEOUT_ID); } #endif