|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2022 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // ADPCM (MSM6258V)
9: //
10:
1.1.1.7 root 11: // ミキサー周波数はこれらがすべて割り切れるよう 62500 [Hz] (= 16 usec)
12: // にする。
13: //
14: // clk div freq mixerfreq に対する倍率
15: // ---- ---- -------- ---
16: // 8MHz 512 15625 4
17: // 8MHz 768 10416.67 6
18: // 8MHz 1024 7812.5 8
19: // 4MHz 512 〃
20: // 4MHz 768 5208.33 12
21: // 4MHz 1024 3906.25 16
22:
23: // ある 16 usec * (freq による倍率) の時間内での書き込みは、このサンプル
24: // の代表値。1期間内に1回しか来ないはず。
25: // かつ、ブロックは 40 msec で割り切れる時間ごとに区切られているため、
26: // 前回の書き込み位置の次、ではなく、現在時刻に応じた位置に書き出す。
27:
1.1 root 28: #include "adpcm.h"
29: #include "dmac.h"
1.1.1.6 root 30: #include "event.h"
1.1.1.8 ! root 31: #include "mainbus.h"
1.1.1.7 root 32: #include "monitor.h"
1.1 root 33: #include "scheduler.h"
1.1.1.7 root 34: #include "sound.h"
1.1 root 35:
36: // コンストラクタ
37: ADPCMDevice::ADPCMDevice()
1.1.1.2 root 38: : inherited(OBJ_ADPCM)
1.1 root 39: {
1.1.1.7 root 40: monitor = gMonitorManager->Regist(ID_MONITOR_ADPCM, this);
1.1.1.8 ! root 41: monitor->SetCallback(&ADPCMDevice::MonitorScreen);
1.1.1.7 root 42: monitor->SetSize(40, 7);
1.1 root 43: }
44:
45: // デストラクタ
46: ADPCMDevice::~ADPCMDevice()
47: {
1.1.1.2 root 48: }
49:
50: // 初期化
51: bool
52: ADPCMDevice::Init()
53: {
54: dmac = GetDMACDevice();
1.1.1.7 root 55:
56: sound = GetSoundRenderer();
57: track = sound->RegistTrack(this);
58: if (track == NULL) {
59: // エラーメッセージは表示済み。
60: return false;
61: }
62:
1.1.1.8 ! root 63: mixer_frame_tsec = 1_sec / sound->GetMixerFreq();
1.1.1.2 root 64:
1.1.1.6 root 65: auto evman = GetEventManager();
66: event = evman->Regist(this,
67: ToEventCallback(&ADPCMDevice::EventCallback),
68: "ADPCM");
1.1.1.4 root 69:
1.1.1.2 root 70: return true;
1.1 root 71: }
72:
73: // リセット
74: void
75: ADPCMDevice::ResetHard(bool poweron)
76: {
1.1.1.7 root 77: StopPlay();
78:
79: stepidx = 0;
80: xprev = 0;
1.1 root 81:
82: // ?
1.1.1.7 root 83: clkMHz = 8;
84: // div は PPI の初期化でセットされるはず。
1.1 root 85: div = 512;
1.1.1.7 root 86:
87: // リセットからコマンド受け付けまで 16 msec (MSM6258.pdf)
1.1 root 88: }
89:
1.1.1.3 root 90: busdata
1.1.1.4 root 91: ADPCMDevice::ReadPort(uint32 offset)
1.1 root 92: {
1.1.1.3 root 93: busdata data;
1.1 root 94:
95: switch (offset) {
96: case 0: // STAT
1.1.1.7 root 97: data = GetSTAT();
1.1.1.3 root 98: putlog(1, "STAT -> $%02x", data.Data());
1.1 root 99: break;
100: case 1: // DATA
1.1.1.8 ! root 101: putlog(0, "Read $%06x (NOT IMPLEMENTED)",
! 102: GetMainbusDevice()->GetPaddr());
1.1.1.7 root 103: data = databuf;
1.1 root 104: break;
105: default:
1.1.1.4 root 106: VMPANIC("corrupted offset=%u", offset);
1.1 root 107: }
108:
1.1.1.3 root 109: // InsideOut p.135
110: const busdata wait = busdata::Wait(18 * 40_nsec);
111: data |= wait;
112:
1.1.1.4 root 113: data |= BusData::Size1;
1.1 root 114: return data;
115: }
116:
1.1.1.3 root 117: busdata
1.1.1.4 root 118: ADPCMDevice::WritePort(uint32 offset, uint32 data)
1.1 root 119: {
120: switch (offset) {
121: case 0: // CMD
122: putlog(1, "CMD <- $%02x", data);
1.1.1.7 root 123: // XXX 同時に立ってるとどうなる?
1.1 root 124: if ((data & REC_START)) {
125: putlog(0, "Start recording (NOT IMPLEMENTED)");
126: }
127: if ((data & PLAY_START)) {
128: StartPlay();
129: }
130: if ((data & STOP)) {
1.1.1.7 root 131: StopPlay();
1.1 root 132: }
133: break;
134: case 1: // DATA
1.1.1.7 root 135: WriteData(data);
1.1 root 136: break;
137: default:
1.1.1.4 root 138: VMPANIC("corrupted offset=%u", offset);
1.1 root 139: }
140:
1.1.1.3 root 141: // InsideOut p.135
142: const busdata wait = busdata::Wait(22 * 40_nsec);
1.1.1.4 root 143:
144: busdata r = wait;
145: r |= BusData::Size1;
146: return r;
1.1 root 147: }
148:
1.1.1.3 root 149: busdata
1.1.1.4 root 150: ADPCMDevice::PeekPort(uint32 offset)
1.1 root 151: {
1.1.1.7 root 152: switch (offset) {
153: case 0: // STAT
154: return GetSTAT();
155:
156: case 1: // DATA
157: return databuf;
158:
159: default:
160: VMPANIC("corrupted offset=%d", offset);
161: }
1.1 root 162: }
163:
1.1.1.4 root 164: bool
165: ADPCMDevice::PokePort(uint32 offset, uint32 data)
166: {
167: return false;
168: }
169:
1.1 root 170: void
1.1.1.8 ! root 171: ADPCMDevice::MonitorScreen(Monitor *, TextScreen& screen)
1.1 root 172: {
1.1.1.7 root 173: int y;
174:
175: // Address: $e92000
176: //
177: // Mode: Recording
178: // Freq: 15625 Hz (clk=8MHz div=1024)
179: // Pan : L R
180:
181: screen.Clear();
182: y = 0;
183:
184: screen.Puts(0, y++, "Address: $e92000");
185: y++;
186: screen.Puts(0, y, "Mode:");
187: if (playing) {
188: screen.Puts(6, y, "Playing");
189: } else {
190: screen.Puts(6, y, "Stopped");
191: }
192: y++;
193:
194: screen.Print(0, y, "Freq: %u Hz", freq);
195: screen.Print(15, y, "(clk=%uMHz div=%u)", clkMHz, div);
196: y++;
197:
198: screen.Print(0, y, "Pan :");
199: screen.Putc(6, y, 'L' | TA::OnOff(panout_L));
200: screen.Putc(8, y, 'R' | TA::OnOff(panout_R));
201: y++;
202: y++;
203:
204: screen.Print(0, y, "Internal: Xprev=%-5d StepIdx=%d", xprev, stepidx);
205: }
206:
207: // STAT レジスタの内容を返す。
208: uint32
209: ADPCMDevice::GetSTAT() const
210: {
211: uint32 data;
212:
213: data = 0x40;
214: if (playing) {
215: data |= STAT_PLAY;
1.1 root 216: }
1.1.1.7 root 217: return data;
218: }
219:
220: // 再生開始。
221: void
222: ADPCMDevice::StartPlay()
223: {
224: putlog(1, "Start playing %uHz", freq);
1.1 root 225:
226: playing = true;
1.1.1.7 root 227: xprev = 0;
228: sound->StartPlay(track);
229:
1.1.1.2 root 230: dmac->AssertREQ(3);
1.1 root 231:
1.1.1.8 ! root 232: event->time = guest_frame_tsec * 2;
1.1.1.2 root 233: scheduler->StartEvent(event);
1.1 root 234: }
235:
1.1.1.7 root 236: // 再生停止。
237: void
238: ADPCMDevice::StopPlay()
239: {
240: if (playing) {
241: putlog(1, "Stop playing");
242: }
243: playing = false;
244:
245: // REQ はどうなる?
246:
247: scheduler->StopEvent(event);
248:
249: sound->StopPlay(track);
250: }
251:
252: // データ書き込み。
253: void
254: ADPCMDevice::WriteData(uint32 data)
255: {
256: if (__predict_false(playing == false)) {
257: // 非再生中の書き込み?
258: putlog(1, "DATA <- $%02x (Not Playing)", data);
259: } else {
260: putlog(2, "DATA <- $%02x", data);
261: }
262: databuf = data;
263: }
264:
1.1 root 265: // イベント
266: void
1.1.1.6 root 267: ADPCMDevice::EventCallback(Event *ev)
1.1 root 268: {
269: if (playing) {
1.1.1.7 root 270: DecodeADPCM(databuf);
271:
272: // 空いたので REQ を上げる。
1.1.1.2 root 273: dmac->AssertREQ(3);
1.1 root 274: }
1.1.1.7 root 275:
1.1.1.8 ! root 276: event->time = guest_frame_tsec * 2;
1.1.1.7 root 277: scheduler->StartEvent(event);
278: }
279:
280: // DACK 信号をアサートする (DMAC から呼ばれる)。
281: // 実際には PEDEC がやってるはず?。
282: // ここではデータの受け渡しが完了したはずなのでその REQ を下げるだけ。
283: void
284: ADPCMDevice::AssertDACK()
285: {
286: dmac->NegateREQ(3);
1.1 root 287: }
288:
1.1.1.7 root 289: // パンアウト L を設定する。PPI から呼ばれる。
1.1 root 290: void
1.1.1.7 root 291: ADPCMDevice::SetPanOutL(bool on)
1.1 root 292: {
1.1.1.7 root 293: panout_L = on;
1.1 root 294: }
295:
1.1.1.7 root 296: // パンアウト R を設定する。PPI から呼ばれる。
1.1 root 297: void
1.1.1.7 root 298: ADPCMDevice::SetPanOutR(bool on)
1.1 root 299: {
1.1.1.7 root 300: panout_R = on;
301: }
302:
303: // サンプリングレートを設定する。PPI から呼ばれる。
304: void
305: ADPCMDevice::SetRate(uint32 rate)
306: {
307: assert(rate < 4);
308:
309: // %11 は %01 と同じになる (Inside p295)
310: if (rate == 3) {
311: rate = 1;
312: }
313:
314: div = 1024 - rate * 256;
315: CalcRate();
1.1 root 316: }
317:
318: // クロック切り替え。OPM から呼ばれる。
319: // CT1 = %0 で 8MHz、%1 で 4MHz。
320: void
321: ADPCMDevice::SetClock(bool ct1)
322: {
323: if (ct1) {
1.1.1.7 root 324: clkMHz = 4;
1.1 root 325: } else {
1.1.1.7 root 326: clkMHz = 8;
327: }
328: CalcRate();
329: }
330:
331: // div と clk から必要なパラメータを計算する。
332: void
333: ADPCMDevice::CalcRate()
334: {
335: // 1フレームにかかる時間。15625 Hz なら 64 usec。
1.1.1.8 ! root 336: guest_frame_tsec = usec_to_tsec(div / clkMHz);
1.1.1.7 root 337:
338: // 周波数。主に表示用。
1.1.1.8 ! root 339: freq = clkMHz * 1000'000U / div;
1.1.1.7 root 340:
341: // アップスケール用の倍率。15625Hz なら 4倍。
1.1.1.8 ! root 342: scale_factor = guest_frame_tsec / mixer_frame_tsec;
1.1.1.7 root 343:
344: // イベント名に載せておく。
345: event->SetName(string_format("ADPCM %u Hz", freq));
346: }
347:
348: // ADPCM ストリームの1バイトをデコードする。(再生)
349: void
350: ADPCMDevice::DecodeADPCM(uint32 data)
351: {
352: int16 s1 = adpcm2pcm_step(data & 0x0f);
353: int16 s2 = adpcm2pcm_step(data >> 4);
354:
355: uint64 vtime = scheduler->GetVirtTime();
356:
357: // 1サンプル目。
358: WritePCM(vtime, s1);
359: // 2サンプル目。
1.1.1.8 ! root 360: WritePCM(vtime + guest_frame_tsec, s2);
1.1.1.7 root 361: }
362:
363: // vtime に相当する位置に PCM データを書き込む。
364: // その際、値は pcm0 から target までを線形補間し、
365: // target を次の pcm0 とする。
366: void
367: ADPCMDevice::WritePCM(uint64 vtime, int16 target)
368: {
1.1.1.8 ! root 369: uint64 vseq = vtime / Sound::BLK_TSEC;
! 370: uint64 voff = vtime % Sound::BLK_TSEC;
1.1.1.7 root 371:
372: // 40msec バッファでは 1バイト (2サンプル) がバッファをまたぐ事があるため、
373: // サンプルごとに行う必要がある。
374: int16 *blkbuf = track->AllocSeq(vseq);
375: assert(blkbuf);
376:
377: // このフレームがミキサーバッファのどの位置か。
378: uint32 mixer_frame_idx =
1.1.1.8 ! root 379: voff / guest_frame_tsec * Sound::NCHAN * scale_factor;
1.1.1.7 root 380: int16 *d = blkbuf + mixer_frame_idx;
381:
382: // ここから scale_factor 個で pcm0 から target になるよう線形補間する。
383: int16 delta = (target - pcm0) / scale_factor;
384: int16 val;
385:
386: val = pcm0;
387: for (uint i = 0; i < scale_factor; i++) {
388: val += delta;
389: *d++ = __predict_true(panout_L) ? val : 0;
390: *d++ = __predict_true(panout_R) ? val : 0;
391: }
392: pcm0 = target;
393: }
394:
395: // エンコード (PCM -> ADPCM) 側は録音方向なので使ってない。
396: //
397: // let Bit3 = Bit2 = Bit1 = Bit0 = 0
398: // if (d(n) < 0)
399: // Bit3 = 1
400: // d(n) = ABS(d(n))
401: // if (d(n) >= ss(n))
402: // Bit2 = 1; d(n) = d(n) - ss(n)
403: // if (d(n) >= ss(n) / 2)
404: // Bit1 = 1; d(n) = d(n) - ss(n) / 2
405: // if (d(n) >= ss(n) / 4)
406: // Bit0 = 1
407: // L(n) = (0b1000 * Bit3) + (0b100 * Bit2) + (0b10 + Bit1) + Bit0
408: inline uint32
409: ADPCMDevice::adpcm_encode(int32 dn)
410: {
411: uint32 Ln = 0;
412:
413: int ss = adpcm_stepsize[stepidx];
414:
415: if (dn < 0) {
416: Ln = 0x8;
417: dn = -dn;
418: }
419: if (dn >= ss) {
420: Ln |= 0x4;
421: dn -= ss;
422: }
423: ss /= 2;
424: if (dn >= ss) {
425: Ln |= 0x2;
426: dn -= ss;
427: }
428: ss /= 2;
429: if (dn >= ss) {
430: Ln |= 0x1;
1.1 root 431: }
1.1.1.7 root 432: return Ln;
1.1 root 433: }
1.1.1.7 root 434:
435: // d(n) = (ss(n) * Bit2) + (ss(n) / 2 * Bit1) + (ss(n) / 4 * Bit0) + (ss(n) / 8)
436: // if (Bit3 = 1)
437: // d(n) = d(n) * (-1)
438: // X(n) = X(n-1) + d(n)
439: inline int32
440: ADPCMDevice::adpcm_decode(uint32 data, int32 xn)
441: {
442: int b3 = (data & 8) ? 1 : 0;
443: int b2 = (data & 4) ? 1 : 0;
444: int b1 = (data & 2) ? 1 : 0;
445: int b0 = (data & 1);
446:
447: int32 ss = adpcm_stepsize[stepidx];
448: int32 dn = (ss * b2) + (ss / 2 * b1) + (ss / 4 * b0) + ss / 8;
449: if (b3) {
450: dn = -dn;
451: }
452:
453: xn += dn;
454:
455: // Saturate in 12 bits.
456: if (__predict_false(xn > 2047)) {
457: xn = 2047;
458: } else if (__predict_false(xn < -2047)) {
459: xn = -2047;
460: }
461:
462: return xn;
463: }
464:
465: inline void
466: ADPCMDevice::adpcm_calcstep(uint32 data)
467: {
468: stepidx += adpcm_stepadj[data];
469: if (__predict_false(stepidx < 0)) {
470: stepidx = 0;
471: } else if (__predict_false(stepidx > 48)) {
472: stepidx = 48;
473: }
474: }
475:
476: uint32
477: ADPCMDevice::pcm2adpcm_step(int16 pcm)
478: {
479: // Input of this algorithm is 12 bit.
480: int32 xn = pcm / 16;
481: int32 dn = xn - xprev;
482: uint32 Ln = adpcm_encode(dn);
483:
484: // next はこの Ln をデコードして PCM にした値
485: xprev = adpcm_decode(Ln, xprev);
486: adpcm_calcstep(Ln);
487:
488: return Ln;
489: }
490:
491: int16
492: ADPCMDevice::adpcm2pcm_step(uint32 data)
493: {
494: int32 xn = adpcm_decode(data, xprev);
495:
496: // next
497: xprev = xn;
498: adpcm_calcstep(data);
499:
500: // このアルゴリズムの出力は(下詰めで) 12 bit。
501: // ただし MSM6258 の出力 DAC は 10 bit 分しかない。
502: xn /= 4;
503: // その 10 bit を 16 bit PCM にする。
504: xn *= 64;
505: return xn;
506: }
507:
508: /*static*/ const int
509: ADPCMDevice::adpcm_stepadj[16] = {
510: -1, -1, -1, -1, 2, 4, 6, 8,
511: -1, -1, -1, -1, 2, 4, 6, 8,
512: };
513:
514: /*static*/ const int32
515: ADPCMDevice::adpcm_stepsize[49] = {
516: 16, 17, 19, 21, 23, 25, 28, 31, 34, 37,
517: 41, 45, 50, 55, 60, 66, 73, 80, 88, 97,
518: 107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
519: 279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
520: 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552,
521: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.