Skip to content

Commit f610f60

Browse files
authored
NDP - PSG driver for MSX (libmsx version) (#87)
* feat(NDP): add NDP driver
1 parent 591a9c7 commit f610f60

26 files changed

Lines changed: 4555 additions & 13 deletions

README.md

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ The below functionality is supported.
7474
- Read/Write registers.
7575

7676
- Sound driver
77+
- NDP - PSG Driver for MSX
78+
- NTSC (60Hz)
79+
- Stop, Start, Pause, Resume, Auto-Repeat.
80+
- NDP was originally programmed and provided by
81+
[naruto2413](https://x.com/naruto2413) and later modified for libmsx by
82+
Daishi Mori ([mori0091](https://x.com/mori0091)).
83+
- The original NDP driver for MSX and MML editor/compiler for Windows are
84+
distributed at the following site by naruto2413.
85+
- See also [NDP - PSG Driver for MSX](https://ndp.squares.net/web/)
7786
- LA0 - a PSG, SCC/SCC+, and OPLL sound driver
7887
- NTSC (60Hz), PAL/SECAM (50Hz), auto detect and auto adjust.
7988
- Available to specify default playing frequency that the sound data author expecting.
@@ -117,19 +126,6 @@ The below functionality is supported.
117126
> See also <https://github.com/einar-saukas/ZX0>.
118127
119128

120-
## Unsupported functionality
121-
122-
The below functionality is NOT supported yet.
123-
124-
- Keyboard input
125-
- Sound output
126-
- ~~PSG (AY-3-8910)~~ `supported`
127-
- ~~OPLL (YM2413 / MSX-MUSIC)~~ `supported`
128-
- ~~BGM driver~~ `supported`
129-
- ~~Sound effect driver~~ `supported`
130-
- … and so on
131-
132-
133129
# Pre-requisites
134130

135131
## Target Machine

include/NDP.h

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
// -*- coding: utf-8-unix -*-
2+
/*
3+
* Copyright (c) 2021-2025 Daishi Mori (mori0091)
4+
*
5+
* This software is released under the MIT License.\n
6+
* See https://github.com/mori0091/libmsx/blob/main/LICENSE
7+
*
8+
* GitHub libmsx project\n
9+
* https://github.com/mori0091/libmsx
10+
*/
11+
/**
12+
* \file NDP.h
13+
* \brief NDP - NDP sound driver
14+
* \ingroup NDP
15+
*/
16+
17+
#ifndef NDP_H_
18+
#define NDP_H_
19+
20+
#include <memfile.h>
21+
22+
/**
23+
* \defgroup NDP NDP - NDP sound driver.
24+
* \ingroup LIBMSX_REPLAYER
25+
* `#include <NDP.h>`
26+
* NDP - PSG Driver for MSX (libmsx version).
27+
*
28+
* This software (NDP - PSG Driver for MSX) was originally programmed and
29+
* provided by naruto2413 and later modified for libmsx by Daishi Mori
30+
* (mori0091).
31+
*
32+
* The original NDP driver for MSX and MML editor/compiler for Windows are
33+
* distributed at the following site by naruto2413.
34+
*
35+
* NDP - PSG Driver for MSX
36+
* https://ndp.squares.net/web/
37+
*/
38+
39+
/**
40+
* \defgroup NDP_REPLAYER The replayer APIs of the NDP sound driver.
41+
* \ingroup NDP
42+
* The replayer APIs of the NDP sound driver.
43+
*
44+
* @{
45+
*/
46+
47+
/**
48+
* `MSX` Initialize the NDP sound driver.
49+
*
50+
* This function must be called once. In particular, it must be called
51+
* before the first call to any other NDP APIs.
52+
*/
53+
void NDP_init(void);
54+
55+
/**
56+
* `MSX` Return the version code of the NDP sound driver.
57+
*
58+
* Return the 2-byte version code `(major << 8) | (minor)`.
59+
*
60+
* If `major` is `0`, it means version “0.9.minor”,
61+
* otherwise it means version “major.minor”.
62+
*
63+
* For example,
64+
* - return `0x010A` for version 1.10
65+
* - return `0x0003` for version 0.9.3
66+
*
67+
* \return version code
68+
*/
69+
uint16_t NDP_version(void);
70+
71+
/**
72+
* `MSX` Main routine of the NDP sound driver.
73+
*
74+
* To play back background music, this function must be called at each VSYNC
75+
* timing.
76+
*
77+
* The easiest way is to set this function as the VSYNC interrupt handler by
78+
* calling set_vsync_handler().
79+
*/
80+
void NDP_play(void);
81+
82+
#if defined(LIBMSX_MEGAROM)
83+
/*
84+
* An alternative version of `NDP_play()` that allows direct playback of song
85+
* data in MegaROM.
86+
*/
87+
void NDP_play_bmem(void);
88+
#define NDP_play NDP_play_bmem
89+
#endif
90+
91+
/**
92+
* `MSX` Start / Resume music.
93+
*
94+
* \sa NDP_fadein()
95+
*/
96+
void NDP_start(void);
97+
98+
#if defined(LIBMSX_MEGAROM)
99+
/*
100+
* An alternative version of `NDP_start()` that allows direct playback of song
101+
* data in MegaROM.
102+
*/
103+
void NDP_start_bmem(void);
104+
#define NDP_start NDP_start_bmem
105+
#endif
106+
107+
/**
108+
* `MSX` Pause music.
109+
*/
110+
void NDP_pause(void);
111+
/**
112+
* `MSX` Return whether paused or not.
113+
*
114+
* \return `true` if paused.
115+
*/
116+
bool NDP_is_paused(void);
117+
118+
/**
119+
* `MSX` Stop music.
120+
*
121+
* \sa NDP_fadeout()
122+
*/
123+
void NDP_stop(void);
124+
125+
/**
126+
* `MSX` Set maximum main-volume.
127+
*
128+
* \param vol Volume (0..15)
129+
*/
130+
void NDP_set_volume(uint8_t vol);
131+
132+
/**
133+
* `MSX` Fade-out and stop music.
134+
*
135+
* \param wait Number of VSYNC frames per step of fade-out (wait count).
136+
*/
137+
void NDP_fadeout(uint8_t wait);
138+
139+
/**
140+
* `MSX` Fade-in and start music.
141+
*
142+
* \param wait Number of VSYNC frames per step of fade-in (wait count).
143+
*/
144+
void NDP_fadein(uint8_t wait);
145+
146+
/**
147+
* `MSX` Return whether BGM is playing or not.
148+
*
149+
* \return `true` if BGM is playing.
150+
*/
151+
bool NDP_is_playing(void);
152+
153+
/**
154+
* `MSX` Return status for each tracks.
155+
*
156+
* \return Status flags.
157+
* - bit #3 Tracks 3 (0: finished, 1: playing)
158+
* - bit #2 Tracks 2 (0: finished, 1: playing)
159+
* - bit #1 Tracks 1 (0: finished, 1: playing)
160+
* - bit #0 Tracks R (0: finished, 1: playing)
161+
*/
162+
uint8_t NDP_get_track_status(void);
163+
164+
/**
165+
* `MSX` Return the loop counter value.
166+
*
167+
* The loop counter starts at 0 and counts up when the song loops back.
168+
*
169+
* In case of overflow (exceeding 255), the counter returns to 0.
170+
*
171+
* \return The loop counter value.
172+
*/
173+
uint8_t NDP_get_loop_counter(void);
174+
175+
/** @} */
176+
177+
// ----------------------------------------------------------------------
178+
/**
179+
* \defgroup NDP_SONG Open NDP song data, and set it in the driver.
180+
* \ingroup NDP
181+
*
182+
* @{
183+
*/
184+
185+
/**
186+
* `MSX` Container of an opened NDP song data.
187+
*/
188+
typedef struct NDPFile {
189+
MemFile mf;
190+
} NDPFile;
191+
192+
/**
193+
* `MSX` Open NDP song data stored in ROM / RAM.
194+
*
195+
* \param ndp Pointer to a NDPFile to be initialized.
196+
* \param loc Location of the NDP song data.
197+
* \param size Size in bytes.
198+
* \return Number of songs contained in the NDP file.
199+
*/
200+
int NDP_open_mem(NDPFile * ndp, const uint8_t * loc, size_t size);
201+
202+
/**
203+
* `MSX` Open NDP song data stored in banked memory (MegaROM).
204+
*
205+
* \param ndp Pointer to a NDPFile to be initialized.
206+
* \param loc Location of the NDP song data.
207+
* \param size Size in bytes.
208+
* \return Number of songs contained in the NDP file.
209+
*/
210+
int NDP_open_bmem(NDPFile * ndp, bmemptr_t loc, uint32_t size);
211+
212+
/**
213+
* `MSX` Open NDP file stored as named resources in banked memory (MegaROM).
214+
*
215+
* \param ndp Pointer to a NDPFile to be initialized.
216+
* \param path Path/File name (*.NDP) of the resource.
217+
* \return Number of songs contained in the NDP file.
218+
*/
219+
int NDP_open_resource(NDPFile * ndp, const char * path);
220+
221+
/**
222+
* `MSX` Setup the NDP song data to NDP sound driver.
223+
*
224+
* If the song data body is in a contiguous area of the current CPU address
225+
* space or within the 16KiB segment boundaries of MegaROM, set the NDP sound
226+
* driver to play directly from that area. Otherwise, fails.
227+
*
228+
* \param ndp Pointer to the NDPFile opened by `NDP_open_*()`.
229+
*
230+
* \return `true` on success, `false` otherwise.
231+
*/
232+
bool NDP_set_bgm(NDPFile * ndp);
233+
234+
/**
235+
* `MSX` Load and setup the NDP song data to NDP sound driver.
236+
*
237+
* If the specified RAM buffer size is large enough, load the song into the
238+
* buffer and set the NDP sound driver to play from the buffer. Otherwise,
239+
* fails.
240+
*
241+
* \param ndp Pointer to the NDPFile opened by `NDP_open_*()`.
242+
* \param buf Pointer to RAM buffer.
243+
* \param buf_size Size of the buffer.
244+
*
245+
* \return `true` on success, `false` otherwise.
246+
*/
247+
bool NDP_load_bgm(NDPFile * ndp, uint8_t * buf, size_t buf_size);
248+
249+
/**
250+
* `MSX` Returns whether or not there is metadata in the NDP song data.
251+
*
252+
* \param ndp Pointer to NDPFile opened by `NDP_open_*()`.
253+
*
254+
* \return `true` if metadata is present, `false` otherwise.
255+
*/
256+
bool NDP_has_metadata(NDPFile * ndp);
257+
258+
/**
259+
* `MSX` Read metadata stored in NDP song data.
260+
*
261+
* If there is metadata in the NDP song data, it is read and written to the
262+
* specified buffer. If successful, the buffer contents will be a concatenation
263+
* of five C strings (zero-terminated Shift-JIS strings).
264+
*
265+
* Each of the five string values corresponds to the following information in
266+
* order
267+
* - Title of the song
268+
* - Composer
269+
* - Arranger
270+
* - Programmer (NDP music data creator)
271+
* - Memo (remarks)
272+
*
273+
* If the buffer size is too short, some items in the buffer will be too short
274+
* or will be invalid strings.
275+
*
276+
* \param ndp Pointer to NDPFile opened by `NDP_open_*()`.
277+
* \param buf Pointer to the buffer into which the metadata will be read.
278+
* \param buf_size Size of the buffer.
279+
*
280+
* \return Size read into the buffer.
281+
*/
282+
size_t NDP_read_metadata(NDPFile * ndp, uint8_t * buf, size_t buf_size);
283+
284+
/** @} */
285+
286+
#endif // NDP_H_

0 commit comments

Comments
 (0)