OXYGENHUB
◆ main openmsx / src / cassette / CassettePlayer.hh
5.5 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef CASSETTEPLAYER_HH
2
#define CASSETTEPLAYER_HH
3
4
#include "CassetteDevice.hh"
5
#include "CassettePlayerCommand.hh"
6
7
#include "BooleanSetting.hh"
8
#include "EmuTime.hh"
9
#include "Filename.hh"
10
#include "MSXMotherBoard.hh"
11
#include "ResampledSoundDevice.hh"
12
#include "Schedulable.hh"
13
#include "ThrottleManager.hh"
14
15
#include "outer.hh"
16
#include "serialize_meta.hh"
17
18
#include <array>
19
#include <cstdint>
20
#include <memory>
21
#include <string>
22
23
namespace openmsx {
24
25
class CassetteImage;
26
class HardwareConfig;
27
class Wav8Writer;
28
29
class CassettePlayer final : public CassetteDevice, public ResampledSoundDevice
30
                           , public MediaProvider
31
{
32
public:
33
	static constexpr std::string_view TAPE_RECORDING_DIR = "taperecordings";
34
	static constexpr std::string_view TAPE_RECORDING_EXTENSION = ".wav";
35
36
public:
37
	explicit CassettePlayer(HardwareConfig& hwConf);
38
	~CassettePlayer() override;
39
40
	// CassetteDevice
41
	void setMotor(bool status, EmuTime time) override;
42
	int16_t readSample(EmuTime time) override;
43
	void setSignal(bool output, EmuTime time) override;
44
45
	// Pluggable
46
	zstring_view getName() const override;
47
	zstring_view getDescription() const override;
48
	void plugHelper(Connector& connector, EmuTime time) override;
49
	void unplugHelper(EmuTime time) override;
50
51
	// SoundDevice
52
	void generateChannels(std::span<float*> buffers, unsigned num) override;
53
	float getAmplificationFactorImpl() const override;
54
55
	// MediaInfoProvider
56
	void getMediaInfo(TclObject& result) override;
57
	void setMedia(const TclObject& info, EmuTime time) override;
58
59
	template<typename Archive>
60
	void serialize(Archive& ar, unsigned version);
61
62
	enum class State : uint8_t { PLAY, RECORD, STOP };
63
64
	// methods to query the status of the player
65
	const Filename& getImageName() const { return casImage; }
66
	[[nodiscard]] State getState() const { return state; }
67
	[[nodiscard]] bool isMotorControlEnabled() const { return motorControl; }
68
69
	/** Returns the position of the tape, in seconds from the
70
	  * beginning of the tape. */
71
	double getTapePos(EmuTime time);
72
73
	/** Returns the length of the tape in seconds.
74
	  * When no tape is inserted, this returns 0. While recording this
75
	  * returns the current position (so while recording, tape length grows
76
	  * continuously). */
77
	double getTapeLength(EmuTime time);
78
79
	friend class CassettePlayerCommand;
80
81
private:
82
	[[nodiscard]] std::string getStateString() const;
83
	void setState(State newState, const Filename& newImage,
84
	              EmuTime time);
85
	void setImageName(const Filename& newImage);
86
	void checkInvariants() const;
87
88
	/** Insert a tape for use in PLAY mode.
89
	 */
90
	void playTape(const Filename& filename, EmuTime time);
91
	void insertTape(const Filename& filename, EmuTime time);
92
93
	/** Removes tape (possibly stops recording). And go to STOP mode.
94
	 */
95
	void removeTape(EmuTime time);
96
97
	/** Goes to RECORD mode using the given filename as a new tape
98
	  * image. Finishes any old recording session.
99
	  */
100
	void recordTape(const Filename& filename, EmuTime time);
101
102
	/** Rewinds the tape. Also sets PLAY mode, because you can't record
103
	  * over an existing tape. (And it won't be useful to implement that
104
	  * anyway.)
105
	  */
106
	void rewind(EmuTime time);
107
	void wind(EmuTime time);
108
109
	/** Enable or disable motor control.
110
	 */
111
	void setMotorControl(bool status, EmuTime time);
112
113
	/** True when the tape is rolling: not in STOP mode, AND [ motorControl
114
	  * is disabled OR motor is on ].
115
	  */
116
	bool isRolling() const;
117
118
	/** If motor, motorControl or state is changed, this method should
119
	  * be called to update the end-of-tape syncPoint and the loading
120
	  * indicator.
121
	  */
122
	void updateLoadingState(EmuTime time);
123
124
	/** Set the position of the tape, in seconds from the
125
	  * beginning of the tape. Clipped to [0, tape-length]. */
126
	void setTapePos(EmuTime time, double newPos);
127
128
	void sync(EmuTime time);
129
	void updateTapePosition(EmuDuration duration, EmuTime time);
130
	void generateRecordOutput(EmuDuration duration);
131
132
	void fillBuf(size_t length, double x);
133
	void flushOutput();
134
	void autoRun();
135
136
	// Schedulable
137
	struct SyncEndOfTape final : Schedulable {
138
		friend class CassettePlayer;
139
		explicit SyncEndOfTape(Scheduler& s) : Schedulable(s) {}
140
		void executeUntil(EmuTime time) override {
141
			auto& cp = OUTER(CassettePlayer, syncEndOfTape);
142
			cp.execEndOfTape(time);
143
		}
144
	} syncEndOfTape;
145
	struct SyncAudioEmu final : Schedulable {
146
		friend class CassettePlayer;
147
		explicit SyncAudioEmu(Scheduler& s) : Schedulable(s) {}
148
		void executeUntil(EmuTime time) override {
149
			auto& cp = OUTER(CassettePlayer, syncAudioEmu);
150
			cp.execSyncAudioEmu(time);
151
		}
152
	} syncAudioEmu;
153
154
	void execEndOfTape(EmuTime time);
155
	void execSyncAudioEmu(EmuTime time);
156
	EmuTime getCurrentTime() const { return syncEndOfTape.getCurrentTime(); }
157
158
	std::array<uint8_t, 1024> buf;
159
160
	double lastX; // last unfiltered output
161
	double lastY; // last filtered output
162
	double partialOut;
163
	double partialInterval;
164
165
	/** The time in the world of the tape. Zero at the start of the tape. */
166
	EmuTime tapePos = EmuTime::zero();
167
168
	/** Last time the sync() method was called.
169
	  * Used to calculate EmuDuration since last sync. */
170
	EmuTime prevSyncTime = EmuTime::zero();
171
172
	// SoundDevice
173
	unsigned audioPos = 0;
174
	Filename casImage;
175
176
	MSXMotherBoard& motherBoard;
177
178
	CassettePlayerCommand cassettePlayerCommand;
179
180
	LoadingIndicator loadingIndicator;
181
	BooleanSetting autoRunSetting;
182
	std::unique_ptr<Wav8Writer> recordImage;
183
	std::unique_ptr<CassetteImage> playImage;
184
185
	size_t sampCnt = 0;
186
	State state = State::STOP;
187
	bool lastOutput = false;
188
	bool motor = false, motorControl = true;
189
	bool syncScheduled = false;
190
};
191
SERIALIZE_CLASS_VERSION(CassettePlayer, 2);
192
193
} // namespace openmsx
194
195
#endif