Thanks to Julio Marchi for this space in MSX All
 

MSX Digitized Sound Generator

  A nice tool to convert PC sounds (samples) to run on MSX PSG. Digitize voices and insert into your app!
Players description - 1-bit and 4-bit formats   In this page we will discuss how MSX is able to reproduce sound (or samples) through PPI and PSG chips. Thus, we will present two sample players for MSX in Assembly with commented code.
  Data reading involves a high frequency which make it impossible to run in Basic. So, all players were developed in Assembly.
Move Data - Moving a sound file to RAM pages 0 and 1   Due to the large amount of data used to reproduce an acceptable sound, a solution adopted by the authors of both Video Hits and Digivoix programs were to move the sound data to RAM page 0 and/or 1. For that, we must change slots configuration on pages 0 and 1, once both are set for ROM use. Slot changing only works fine using Assembly language.
  Video Hits program is able to move up to two blocks of 16 KB each to pages 0 and 1. This program performs an intelligent way to load sound files, once it loads a binary file on RAM addresses from &H9000 to &HCFFF (as Video Hits code in Basic is short, this area is free) and then moves the data to RAM page 0 or 1 using a simple Assembly program.
  Nevertheless, Digivoix makes use of a text file for sound data. It loads small blocks of data and then copies them to page 1 in a quite similar way to Video Hits. This combination of data reading results on about 30 minutes to finish for a 16 KB data file. In contrast, Video Hits takes only a few seconds to load and move the same amount of data to page 0 or 1.

  The next program in Assembly moves a block from &H9000-&HCFFF to RAM page 0. This code is compatible with any MSX with RAM on page 0 and RAM in any primary slot.
Add  Machine code Line          Mnemonics         Comments
-------------------------------------------------------------------------------------
D100  		   10 		ORG  &HD100	; Program initial address
D100  F3	   20 		DI 		; Disable interruptions
D101  DB A8	   30 		IN   A,(&HA8)	; Read slots configuration
D103  5F	   40 		LD   E,A	; Save in E
D104  06 04	   50 		LD   B,4	; 
D106  CB 3F	   60 ROT1:	SRL  A		; Do A >> 4
D108  10 FC	   70 		DJNZ ROT1	;
D10A  83	   80 		ADD  A,E	; Join A and E
D10B  D3 A8	   90 		OUT  (&HA8),A	; Configure RAM in all slots
D10D  21 00 90	  100 		LD   HL,&H9000	; Source
D110  11 00 00	  110 		LD   DE,&H0000	; Destiny
D113  01 00 40	  120 		LD   BC,&H4000	; Length
D116  ED B0	  130 		LDIR 		; Move a block
D118  DB A8	  140 		IN   A,(&HA8)	; Read slots configuration
D11A  E6 F0	  150 		AND  &HF0	; Filter to enable ROM
D11C  D3 A8	  160 		OUT  (&HA8),A	; Change to RAM RAM ROM ROM
D11E  FB	  170 		EI 		; Enable interruptions
D11F  C9	  180 		RET 		; Return to Basic

  If you want to move data to page 1, change address &HD112 value to &H40. The next program in Basic shows how to move a block to pages 0 and 1.
10 BLOAD"MVDATA.BIN"
20 DEFUSR=&HD100
30 BLOAD"BLOCO1.SND"
40 X=USR(0)
50 BLOAD"BLOCO2.SND"
60 POKE &HD112,&H40
70 X=USR(0)
MarMSX SND (1-bit) - sound through PPI key click   MSX PPI port C is able to enable a key click through bit 7 [1]. See the diagram below [1].
PPI Port C (I/O Port AAH)

   7     6     5     4     3     2     1     0
┌─────┬─────┬─────┬─────┬───────────────────────┐
│ Key │ Cap │ Cas │ Cas │  Keyboard Row Select  │
│Click│ LED │ Out │Motor│                       │
└─────┴─────┴─────┴─────┴───────────────────────┘
  As the MSX Red Book [1] indicates, the key click output is attenuated and mixed with the audio output from the Programmable Sound Generator. To actually generate a sound this bit should be flipped on and off.
  In fact, a click sound is only generated when the register bit 7 state is changed. If we change this bit from 0 to 1, a strong click is produced and its value is attenuated until silence, except if the bit state is changed. When the state is changed from 1 to 0, a weak click is produced and attenuated until silence, also except for state changing. For each event, the frequency is about 100 Hz.
  The next picture illustrates that. Take a look on bit 7 value trough time line. When a state changes (transition between 0-1), there is a pulse generation (one up, other down).   Based on Video Hits and Digivoix players, we propose the player presented below. This player has some important improvements like slot changing on any MSX, as well as the correct PPI bit setting, preserving original data on it.
Add  Machine code Line          Mnemonics         Comments
-------------------------------------------------------------------------------------
D000  		   10 		ORG  &HD000	; Starting address
D000  F3	   20 		DI 		; Disable interruption
D001  DB A8	   30 		IN   A,(&HA8)	; Read slots configuration
D003  5F	   40 		LD   E,A	; Save on register E
D004  06 04	   50 		LD   B,4	; 
D006  CB 3F	   60 ROT:	SRL  A		; Shift left A 4 times
D008  10 FC	   70 		DJNZ ROT	;
D00A  83	   80 		ADD  A,E	; Add A to E
D00B  D3 A8	   90 		OUT  (&HA8),A	; Set all slots as RAM
D00D  21 00 00	  100 		LD   HL,0	; PCM initial data
D010  4E	  110 LOOP:	LD   C,(HL)	; Read the next octet (8 samples)
D011  06 08	  120 		LD   B,8	; Repeat 8x
D013  CB 11	  130 LPI:	RL   C		; Shift 1 bit to left
D015  DB AA	  140 		IN   A,(&HAA)	; Read PPI port C state
D017  38 04	  150 		JR   C,TONE	; Check if CY=1
D019  E6 7F	  160 		AND  &H7F	; If not, click=0
D01B  18 02	  170 		JR   CHTONE	; Jumps to CHtone
D01D  F6 80	  180 TONE:	OR   &H80	; If yes, click=1
D01F  D3 AA	  190 CHTONE:	OUT  (&HAA),A	; Sen result to PPI
D021  1E 0E	  200 		LD   E,14	; Create a delay of 14
D023  1D	  210 DELAY:	DEC  E		;
D024  20 FD	  220 		JR   NZ,DELAY	; Delay
D026  10 EB	  230 		DJNZ LPI	;
D028  23	  240 		INC  HL		; Next octet (data)
D029  7C	  250 		LD   A,H	;
D02A  FE 40	  260 		CP   &H40	; Check if HL=&H4000
D02C  20 E2	  270 		JR   NZ,LOOP	; If not, go to LOOP
D02E  DB A8	  280 		IN   A,(&HA8)	; Read slots configuration
D030  E6 F0	  290 		AND  &HF0	; Filter to set ROM on pgs 0 and 1
D032  D3 A8	  300 		OUT  (&HA8),A	; Change
D034  FB	  310 		EI 		; Enable interruptions
D035  C9	  320 		RET		; Return to Basic
  The first step is to set all pages to RAM (lines 30-90) in order to use page 0 or 1. The sound files are quite large and we recommend to make use of this RAM place not used by Basic.
  Then, we point to initial data address and read the first byte. Once this format is 1 bit, we must read all the 8 bits from this byte. The shift instruction RL shifts left one bit and move the bit 7 to the carry flag. So, the carry flag value indicates the click state.
  Digivoix has an option to make fun on sound (change voice), by replacing this left shift to a corresponding right shift.
  For each bit read and executed, we make a pause. The delay is used to synchronize the execution frequency with PCM sound frequency. For example, Video Hits delay of 14 corresponds to a frequency of 11,131 Hz.
  After reading the byte, we check if the end of data was reached. If not, repeat sound reading and execution operation.
  When the reading ends, we return slots to the original state with ROM on pages 0 and 1.

  Program in Basic to load a sound file, move data and play.
10 BLOAD"SOUND.SND"
20 BLOAD"MVDATA.BIN"
30 DEFUSR=&HD100
40 X=USR(0)
50 BLOAD"SND.BIN"
60 DEFUSR=&HD000
70 X=USR(0)
MarMSX S4b (4-bit) - sound through PSG   Here, we will use the PSG volume to reproduce a wave sound.
  Each PSG sound channel is able to discriminate 16 volume levels, which allow us to represent a wave sound using 4 bits. Now, the original wave can be modeled more precisely than the 1-bit format. Nevertheless, this format has a high cost: the file size is 4 times greater than the 1-bit format.
  For generating a sound, we will set the highest possible frequency, once PSG do not generate clicks like PPI. In this case, we will create an envelope over the tone signal.
  We will use the PSG channel A and set its frequency to 0. The program will then read data and change channel A volume, according to the values read.

  An Assembly program to play 4-bit sounds is presented below.
Add  Machine code Line          Mnemonics         Comments
-------------------------------------------------------------------------------------
D000  		   10 		ORG  &HD000	; Initial address
D000  F3	   20 		DI 		; Disable interruptions
D001  3E 07	   30 		LD   A,7	; Set register 7 (mixer)
D003  D3 A0	   40 		OUT  (&HA0),A	;
D005  3E BE	   50 		LD   A,190	; Mixer value - enable channel A
D007  D3 A1	   60 		OUT  (&HA1),A	;
D009  AF	   70 		XOR  A		; Register 0
D00A  D3 A0	   80 		OUT  (&HA0),A	;
D00C  3E 00	   90 		LD   A,0	; LO period in A = 0
D00E  D3 A1	  100 		OUT  (&HA1),A	;
D010  3E 01	  110 		LD   A,1	; Register 1
D012  D3 A0	  120 		OUT  (&HA0),A	;
D014  AF	  130 		XOR  A		; HI period in A = 0
D015  D3 A1	  140 		OUT  (&HA1),A	;
D017  DB A8	  150 		IN   A,(&HA8)	; Read slots configuration
D019  5F	  160 		LD   E,A	; Save in E
D01A  06 04	  170 		LD   B,4	;
D01C  CB 3F	  180 ROT:	SRL  A		; Do A >> 4
D01E  10 FC	  190 		DJNZ ROT	;
D020  83	  200 		ADD  A,E	; Join values
D021  D3 A8	  210 		OUT  (&HA8),A	; Set all slots as RAM
D023  21 00 00	  220 		LD   HL,0	; Data initial address
D026  06 02	  230 LOOP:	LD   B,2	; Read 2 nibbles
D028  1E 00	  240 		LD   E,0	; E stores A
D02A  3E 08	  250 LPI:	LD   A,8	; Selects register 8
D02C  D3 A0	  260 		OUT  (&HA0),A	;
D02E  7B	  270 		LD   A,E	; Recover saved value
D02F  ED 6F	  280 		RLD 		; Rotates A with (HL)
D031  D3 A1	  290 		OUT  (&HA1),A	; Change volume
D033  5F	  300 		LD   E,A	; Save A in E
D034  16 0E	  310 		LD   D,14	;
D036  15	  320 DELAY:	DEC  D		; Delay of 14
D037  20 FD	  330 		JR   NZ,DELAY	;
D039  10 F4	  340 		DJNZ LPI	; Next B
D03B  ED 6F	  350 		RLD 		; Additional to recover (HL)
D03D  23	  360 		INC  HL		; Next sound data
D03E  7C	  370 		LD   A,H	; 
D03F  FE 40	  380 		CP   &H40	; Check if HL=end
D041  20 E3	  390 		JR   NZ,LOOP	; If not, LOOP
D043  3E 08	  400 		LD   A,8	; Register 8
D045  D3 A0	  410 		OUT  (&HA0),A	;
D047  AF	  420 		XOR  A		; Volume 0
D048  D3 A1	  430 		OUT  (&HA1),A	;
D04A  DB A8	  440 		IN   A,(&HA8)	; Read slots
D04C  E6 F0	  450 		AND  &HF0	; Do RAM RAM ROM ROM
D04E  D3 A8	  460 		OUT  (&HA8),A	;
D050  FB	  470 		EI 		; Enable interruptions
D051  C9	  480 		RET 		; Return to Basic
  Important note: according to the MSX Red Book [1], PSG register 7 must always contain 10xxxxxx or possible damage could result to the PSG. In this case, bit 6 is always 0 and bit 7 is always 1.

  Program in Basic to load a sound file, move data and play.
10 BLOAD"SOUND.S4B"
20 BLOAD"MVDATA.BIN"
30 DEFUSR=&HD100
40 X=USR(0)
50 BLOAD"S4B.BIN"
60 DEFUSR=&HD000
70 X=USR(0)
MarMSX S4b Plus (4-bit) - plays the three channels of PSG   The plus version of S4b was launched in January 2022. Now, all the three PSG channels are used.

  The program in Assembly to play 4-bit sounds with three channels is presented below.
Add  Machine code Line          Mnemonics                 Comments
-------------------------------------------------------------------------------------
D000  		   10 		ORG  &HD000		; Initial address
D000  F3	   20 		DI 			; Disable interruptions
D001  3E 07	   30 		LD   A,7		; Set register 7 (mixer)
D003  D3 A0	   40 		OUT  (&HA0),A		;
D005  3E B8	   50 		LD   A,&B10111000	; Mix value
D007  D3 A1	   60 		OUT  (&HA1),A		;  set channels A,B,C
D009  06 07	   70 		LD   B,7		;
D00B  78   	   80 LPSG:	LD   A,B		;
D00C  3D   	   90 		DEC  A			; Set all periods
D00D  D3 A0	  100 		OUT  (&HA0),A		; 
D00F  AF   	  110 		XOR  A			; to value zero
D010  D3 A1	  120 		OUT  (&HA1),A		;
D012  10 F7	  130 		DJNZ LPSG		;
D014  DB A8	  140 		IN   A,(&HA8)		; Read slot conf.
D016  5F	  150 		LD   E,A		; Save in E
D017  06 04	  160 		LD   B,4		;
D019  CB 3F	  170 ROT:	SRL  A			; Do A >> 4
D01B  10 FC	  180 		DJNZ ROT		;
D01D  83	  190 		ADD  A,E		; Join values
D01E  D3 A8	  200 		OUT  (&HA8),A		; Set all slots as RAM
D020  21 00 00	  210 		LD   HL,0		; Data initial address
D023  06 02	  220 LOOP:	LD   B,2		; Read 2 nibbles
D025  1E 00	  230 		LD   E,0		; E stores A
D027  7B	  240 LPI:	LD   A,E		; Recover saved value
D028  ED 6F	  250 		RLD 			; Rotates A with (HL)
D02A  4F   	  260 		LD   C,A 		; Save in C
D02B  3E 08	  270 		LD   A,8		; Select register 8 (ch. A)
D02D  D3 A0	  280 		OUT  (&HA0),A		;
D02F  79   	  290 		LD   A,C 		; Recover A
D030  D3 A1	  300 		OUT  (&HA1),A		; Change volume
D032  3E 09	  310 		LD   A,9		; Select register 9 (ch. B)
D034  D3 A0	  320 		OUT  (&HA0),A		;
D036  79   	  330 		LD   A,C 		; Recover A
D037  D3 A1	  340 		OUT  (&HA1),A		; Change volume
D039  3E 0A	  350 		LD   A,10		; Select register 10 (ch. C)
D03B  D3 A0	  360 		OUT  (&HA0),A		;
D03D  79   	  370 		LD   A,C 		; Recover A
D03E  D3 A1	  380 		OUT  (&HA1),A		; Change volume
D040  5F	  390 		LD   E,A		; Save A in E
D041  16 0E	  400 		LD   D,14		;
D043  15	  410 DELAY:	DEC  D			; Delay of 14
D044  20 FD	  420 		JR   NZ,DELAY		;
D046  10 DF	  430 		DJNZ LPI		; Next B
D048  ED 6F	  440 		RLD 			; Rotate to recover (HL)
D04A  23	  450 		INC  HL			; Next sound data
D04B  7C	  460 		LD   A,H		; 
D04C  FE 40	  470 		CP   &H40		; Check if HL=end
D04E  20 D3	  480 		JR   NZ,LOOP		; If not, LOOP
D050  DB A8	  490 		IN   A,(&HA8)		; Read slots
D052  E6 F0	  500 		AND  &HF0		; Do RAM RAM ROM ROM
D054  D3 A8	  510 		OUT  (&HA8),A		;
D056  FB	  520 		EI 			; Enable interruptions
D057  CD 90 00	  530 		CALL &H90		; Reset PSG (clear volumes)
D05A  C9	  540 		RET 			; Return to Basic
  Both loading procedure and file format are the same of S4b normal version. Nevertheless, the delay and frequency relationship is different. Check out the conv_table.txt file which follows the program.

  The players MarMSX SND, MarMSX S4b and MarMSX S4b Plus and the Move Data program were created by Marcelo Silveira and they are under GNU-GPL v. 3.x license - http://www.gnu.org/licenses/gpl-3.0.txt.



  References:

  1. The MSX Red Book, Avalon Software. McGraw Hill.
  2. Video Hits, produced by Grupo CPM, Brazil.
  3. Digivoix, produced by Hartard Frederic and publish on frech magazine Hebdogiciel,
numbers 164 to 168, 1986.


Marcelo Silveira
Systems and Computing Engineer
Expert in Image Processing and Artificial Intelligence
© MarMSX 1999-2025