File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / adpcm.h
Revision 1.1.1.7 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:06:01 2026 UTC (3 months ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
nono 1.7.0

//
// nono
// Copyright (C) 2022 nono project
// Licensed under nono-license.txt
//

//
// ADPCM (MSM6258V)
//

#pragma once

#include "device.h"

class DMACDevice;
class SoundRenderer;
class SoundTrack;

class ADPCMDevice : public IODevice
{
	using inherited = IODevice;

	static const uint32 baseaddr = 0xe92000;

	static const uint8 STAT_PLAY	= 0x80;

	static const uint8 REC_START	= 0x04;
	static const uint8 PLAY_START	= 0x02;
	static const uint8 STOP			= 0x01;

 public:
	ADPCMDevice();
	~ADPCMDevice() override;

	bool Init() override;
	void ResetHard(bool poweron) override;

	// CT1 によるクロック切り替え。OPM から呼ばれる。
	void SetClock(bool);

	// DMAC から呼ばれる。
	void AssertDACK();

	// PPI
	bool GetPanOutL() const	{ return panout_L; }
	bool GetPanOutR() const	{ return panout_R; }
	void SetPanOutL(bool on);
	void SetPanOutR(bool on);
	void SetRate(uint32 idx);

 protected:
	// BusIO インタフェース
	static const uint32 NPORT = 2;
	busdata ReadPort(uint32 offset);
	busdata WritePort(uint32 offset, uint32 data);
	busdata PeekPort(uint32 offset);
	bool PokePort(uint32 offset, uint32 data);

 private:
	DECLARE_MONITOR_SCREEN(MonitorScreen);

	uint32 GetSTAT() const;
	void StartPlay();
	void StopPlay();
	void WriteData(uint32 data);
	void CalcRate();

	void EventCallback(Event *);

	void DecodeADPCM(uint32 data);
	void WritePCM(uint64 vtime, int16 target);

	uint32 pcm2adpcm_step(int16 pcm);
	int16 adpcm2pcm_step(uint32 data);
	inline uint32 adpcm_encode(int32 dn);
	inline int32  adpcm_decode(uint32 data, int32 xn);
	inline void adpcm_calcstep(uint32 data);

	bool playing {};
	int clkMHz {};			// 入力クロック[MHz] (4 or 8)
	int div {};				// 512, 768, 1024

	bool panout_L {};
	bool panout_R {};

	// 選択周波数での 1フレームにかかる時間 [tsec]
	uint64 guest_frame_tsec {};

	// 周波数
	uint32 freq {};

	// データバッファ(1バイト)
	uint8 databuf {};

	// ADPCM<->PCM 変換
	int32 xprev {};
	int stepidx {};

	// 最後に書き込んだサンプル値 (線形補間用)
	int16 pcm0 {};

	// ミキサー周波数での1フレームにかかる時間 [tsec]
	uint64 mixer_frame_tsec {};

	// ミキサー周波数にアップスキャンするための倍率。
	// 15625 Hz なら 4(倍)。
	uint scale_factor {};

	DMACDevice *dmac {};
	SoundRenderer *sound {};
	SoundTrack *track {};

	Event *event {};
	Monitor *monitor {};

	static const int   adpcm_stepadj[16];
	static const int32 adpcm_stepsize[49];
};

inline ADPCMDevice *GetADPCMDevice() {
	return Object::GetObject<ADPCMDevice>(OBJ_ADPCM);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.