This is a PSG sound driver for MSX.
It is in a form that can be compiled with z88dk (zcc).
Supported functions are as follows:
- Supports interrupted playback of sound effects
- Playback priority can be set for sound effects
- Supports noise ON/OFF, tone, noise tone, volume, and detuning
- Data created with LovelyComposer can be converted with
lc2asm.py
(with restrictions)
You can check the execution sample with WebMSX at the following URL.
Edit the CMakeLists.txt
included in this project to specify the source for this player (psgdriver.asm
) and the source you created.
For example, the sample program defines the following.
add_source_files(
./src/msx/sample.asm
./src/msx/psgdriver.asm
)
Next, run the following command in the project root directory to generate the make file.
(First time only; not necessary after the second time)
$ mkdir build && cd build
$ cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/z88dk.cmake ..
Execute the following command in the build
directory to build.
$ make clean && make
The .rom
file will be created in the dist
directory.
Enter the source directory and execute the following command (replace the source file name with your own)
This command is the same for both assembler and C.
For details on other options, such as specifying the path to the include file, see the help displayed by zcc -h
.
$ zcc +msx -create-app -subtype=rom psgdriver.asm sample.asm -o=../../dist/build.rom
You can also use z88dk-z80asm or other assemblers included in z88dk.
See z88dk-z80asm documentation for more information.
Other assemblers also use few z88dk-specific features such as macros, which can be handled with a few modifications.
Note :
The area after the label definition part below is a work area.
If you compile with >zcc, it will be properly addressed, otherwise specify ORG to be addressed to RAM area($8000~, etc.).
- SOUNDDRV_WORKAREA : 120byte
This breakdown is as follows. (do not change the order of placement)
- SOUNDDRV_H_TIMI_BACKUP : 5byte
- SOUNDDRV_STATE : 1byte
- SOUNDDRV_WK_MIXING_TONE : 1byte
- SOUNDDRV_WK_MIXING_NOISE : 1byte
- SOUNDDRV_BGMWK : 48byte
- SOUNDDRV_DUMMYWK : 16byte
- SOUNDDRV_SFXWK : 48byte
- At the beginning of the program source you have created, add the following definition:
EXTERN SOUNDDRV_INIT
EXTERN SOUNDDRV_EXEC
EXTERN SOUNDDRV_BGMPLAY
EXTERN SOUNDDRV_SFXPLAY
EXTERN SOUNDDRV_STOP
EXTERN SOUNDDRV_PAUSE
EXTERN SOUNDDRV_RESUME
EXTERN SOUNDDRV_STATUS
- Next, CALL the driver initialization routine (
SOUNDDRV_INIT
) in the initial processing of the program.- In this initialization routine, the H.TIMI hook code (5 bytes) is backed up and rewritten to run the driver.
- If your program has a process that runs on the
H.TIMI
hook, be sure to make a 5-byte backup fromH.TIMI
yourself andJP
to the backed up address at the end of the process. - Note that the timing of
CALL
of this driver's initialization routine by the application can be either before or after theH.TIMI
hook is rewritten.
CALL SOUNDDRV_INIT ; Initialize sound driver
- See the following "Driver API" section.
After the above preparation, the driver can be controlled by following the steps below.
SOUNDDRV_BGMPLAY
- Starts playing BGM.
- Specify the address of the BGM data to be played in the
HL
register.
LD HL,BGMDATA
CALL SOUNDDRV_BGMPLAY ; BGM data play start
SOUNDDRV_SFXPLAY
- Play the sound effect.
- If a sound effect with a higher priority than the specified sound effect is being played, it is not played.
- When the playback of the sound effect is finished, the BGM playback is restored.
- Specify the address of the sound effect data to be played in the
HL
register.
LD HL,SFXDATA
CALL SOUNDDRV_SFXPLAY ; SFX data play start
SOUNDDRV_STOP
- Stops the playback of background music and sound effects.
CALL SOUNDDRV_STOP ; BGM and SFX stop
SOUNDDRV_PAUSE
- Pause playback of background music and sound effects.
CALL SOUNDDRV_PAUSE : BGM and SFX pause
SOUNDDRV_RESUME
- Unpause BGM and sound effects.
- If called during playback, nothing is processed.
CALL SOUNDDRV_RESUME ; BGM and SFX unpause
SOUNDDRV_STATUS
- Obtain driver status.
- Bit 0 is 1 if playback is in progress and 0 if stopped.
- Bit 1 is set to 1 if the program is paused, otherwise it is set to 0.
LD A,(SOUNDDRV_STATUS) ; get driver status
The data structure handled by this driver is the following image.
Both BGM and sound effects will have the same composition.
[BGM/SFX Data]
+- [Priority]
+- [Track 1 data address]
+- [Track 2 data address]
+- [Track 3 data address]
[Track 1 data]
[Track 2 data]
[Track 3 data]
In other words, data created as sound effects can be played as background music, and vice versa.
Also, as described above, since a collection of track data is used as song data, the same track can be used for multiple background music/sound effects.
The BGM/SFX data consists of the following:
- priority(1byte):0~255 (Low to high) Effective only when playing sound effects; ignored for background music.
- Track 1 data address(2byte):If not, set
$0000
. - Track 2 data address(2byte):If not, set
$0000
. - Track 3 data address(2byte):If not, set
$0000
.
The track data consists of the following:
Command | Function | Overview |
---|---|---|
0〜95 ($00〜$5F) |
note number (See "Note Number Table" below for setting values) |
Specified in the format 0 to 95,. The value specifies the note length (n/60). See "About Tone Length" below for more information about note length. |
200〜215 ($CB〜$D7) |
volume | Corresponds to command values 0 to 15. (Same as the value set in PSG registers #8 to #10) |
216 ($D8) |
noise tone | Specified in the format of 216,. Specify 0 to 31 for the value. (Same as the value set in PSG register #6) |
217 ($D9) |
mixing | Specified in the format of 217,. Specify 0 to 3 for the value. (bit0=Tone/bit1=Noise, 1=off/0=on) Example) %10 = Tone ON, Noise OFF |
218 ($DA) |
detune | Specified in the format 218,. The value specifies the correction value for the note. |
253 ($FD) |
start of loop position | When looping at the end of data, the loop starts with the data at this address. |
254 ($FE) |
End of data (return to track start or loop start position) | Returns to the position specified by command 243. If there is no command 243, returns to the beginning. |
255 ($FF) |
End of data (end of playback) | (none) |
The note number (scale) is set to the following tone table value.
octave | C | C+ (D-) |
D | D+ (E-) |
E | F | F+ (G-) |
G | G+ (A-) |
A | A+ (B-) |
B |
---|---|---|---|---|---|---|---|---|---|---|---|---|
o1 | $00 | $01 | $02 | $03 | $04 | $05 | $06 | $07 | $08 | $09 | $0A | $0B |
o2 | $0C | $0D | $0E | $0F | $10 | $11 | $12 | $13 | $14 | $15 | $16 | $17 |
o3 | $18 | $19 | $1A | $1B | $1C | $1D | $1E | $1F | $20 | $21 | $22 | $23 |
o4 | $24 | $25 | $26 | $27 | $28 | $29 | $2A | $2B | $2C | $2D | $2E | $2F |
o5 | $30 | $31 | $32 | $33 | $34 | $35 | $36 | $37 | $38 | $39 | $3A | $3B |
o6 | $3C | $3D | $3E | $3F | $40 | $41 | $42 | $43 | $44 | $45 | $46 | $47 |
o7 | $48 | $49 | $4A | $4B | $4C | $4D | $4E | $4F | $50 | $51 | $52 | $53 |
o8 | $54 | $55 | $56 | $57 | $58 | $59 | $5A | $5B | $5C | $5D | $5E | $5F |
Tone can be obtained by:
- Note length per second: tempo / 60
- Quarter note length: 60 / (note length per second)
- Eighth note length: quarter note length / 2
- 16th note length: 8th note length / 2
Example: Tempo = 120 (= speed of 120 quarter notes per minute)
- Note length per second: 120 / 60 = 2
- Quarter note length: 60 / 2 = 30
- Eighth note length: 30 / 2 = 15
- 16th note length: 15 / 2 = 7.5
Set an integer for the data. If there are decimals, adjust so that the sum is the sum of the note lengths.
A tool is available to convert data created with the "LovelyComposer" composition tool into data for this driver. (src/python/lc2asm.py
)
Python is required, so please install it separately.
LovelyComposer can be purchased at the following sites.
BOOTH
itch.io
Go to the directory where lc2asm.py is located and run the following to create an .asm file at the location where the .jsonl file is located.
python lc2asm.py <.jsonl filepath>
The created .asm file should be imported directly into the source or INCLUDE
.
The options that can be specified are as follows:
- --outfile/-o : Specify output file path
- --force/-f : overwrite output file
- --version/-v : display version
- --help/-h : display help
The following features of LovelyComposer are supported:
- Supports volume specification for each note
- Loop start/end position specification
- Change the number of notes per page and tempo
Data conversion has the following limitations to LovelyComposer's functionality:
- The two available tones are "SQUARE WAVE" and "NOISE".
- The three available channels are 1-3. Channel 4 and code channels are ignored.
- Tempo is not an exact match, but an approximation.
- The pan specification is ignored.
2023/06/11 Version 1.6.1
- lc2asm.py
- Fixed a bug that caused output file labels to be full paths.
2023/06/10 Version 1.6
- lc2asm.py
- Corrected processing around input and output file paths, added options
2023/02/12 Version 1.5.1
- psgdriver.asm
- Abolished "include" and added a label at the beginning of the work area
2022/08/14 Version 1.5.0
- psgdriver.asm
- Added pause (
SOUNDDRV_PAUSE
)/resume (SOUNDDRV_RESUME
) API - Added API (SOUNDDRV_STATUS) to obtain driver status
- Added pause (
2022/08/06 Version 1.4.1
- psgdriver.asm
- Fixed path delimiter error in includes
2022/07/24 Version 1.4.0
- psgdriver.asm
- SFX playback now also determines the priority of the BGM.
(SFX will not be played while BGM with the highest priority is playing.)
- SFX playback now also determines the priority of the BGM.
2022/05/29 Version 1.3.0
- psgdriver.asm
- Version notation modified to match semantic versioning
- Modified to save backup and CALL at the end of processing to allow call chaining of H.TIMI hooks.
- lc2asm.py
- Version notation modified to match semantic versioning
2022/05/07 Version 1.20
- psgdriver.asm
- Volume data configuration changes, along with data changes for other commands.
Please note that this is not compatible with the previous version up to 1.1.
- Volume data configuration changes, along with data changes for other commands.
- lc2asm.py
- Support for volume data configuration changes, as well as data changes for other commands.
2021/12/04 Version 1.11
- lc2asm.py
- Support for changing the number of notes and SPEED values per page and the number of all pages.
2021/11/28 Version 1.10
- psgdriver.asm
- LovelyComposer's support for specifying the loop start/end position
- lc2asm.py
- Modified to output data with loop when end of loop is specified, and without loop when not specified.
2021/11/19 Version 1.00
- psgdriver.asm
- initial creation
- lc2asm.py
- initial creation