playing samples on msx

Page 2/4
1 | | 3 | 4

By [D-Tail]

Ascended (8239)

[D-Tail]'s picture

05-09-2005, 21:57

ARTRAG: wouldn't such a thing consume up to all CPU resources? As in, it isn't possible to play PSG-samples in a game? I recall many people saying that it's even hard for turboR's PCM to keep up... Curious!

By ARTRAG

Enlighted (6428)

ARTRAG's picture

05-09-2005, 23:03

My proposal isn’t heavier than the usual play routine at http://map.tni.nl/articles/psg_sample.php.
All the complexity is in the encoding that should be done by a PC.
Actually the problem is that even the normal player is almost unbearable for any true interactive
application, even if dvick has done an excellent demo paying samples on z80!!!
Nevertheless, you can have PSG samples in the intros....

By SLotman

Paragon (1221)

SLotman's picture

06-09-2005, 06:04

There are tons of ways of playing samples on MSX Smile

Wasiest one, is turbo-R, using PCM Smile
There's also MSX Audio, but I dont know how that works since I dont have one Tongue

There are "ready sample players" for PSG, look for MUST by Ricardo Bittencourt! (I also use the same "must technology" in a routine made by Adriano on my game "Show do Milhão", with very nice results)

By ARTRAG

Enlighted (6428)

ARTRAG's picture

06-09-2005, 16:31

I do not think anyone has proposed something very different from a player that chooses the PSG levels sample per sample, independently from the previous decisions(like the one at TNI).

BTW do you have any link for MUST by Ricardo Bittencourt ?

By norakomi

Paragon (1084)

norakomi's picture

06-09-2005, 16:43


There are "ready sample players" for PSG, look for MUST by Ricardo Bittencourt! (I also use the same "must technology" in a routine made by Adriano on my game "Show do Milhão", with very nice results)
cewl, Id like to have a look at that game, if possible.......

By NYYRIKKI

Enlighted (5588)

NYYRIKKI's picture

09-09-2005, 18:31

As questions about samples are asked every once in a while, I decited to write a quite a complete article about this issue. Let's see if I can make the biggest forum post posted so far Tongue

I hope you find this interesting, this document also contains some new information about SCC.


Playing samples on MSX & Z80. 0.9b Made by: NYYRIKKI 2005
---------------------------------------------------------

There are many ways to play samples on MSX. MSX-Audio and Moonsound has even 
dedicated hardware to play samples, but these hardware solutions are not in 
scope of this document.

From this document you'll find, how to play samples following on devices:

- Covox / SIMPL
- MSX tR PCM
- Music Module
- Key click
- MSX-Music
- PSG
- Konami SCC

At the end of the document you'll find also some tips to get timing right.

In this document every example plays 8bit unsigned sample located in 
#C000-#CFFF at about 8KHz frequency. To load these examples from BASIC, 
you can use following program:

10 'LOADER.BAS
20 IF PEEK(&HF677)<>&HD4 THEN POKE &HF677,&HD4:POKE&HD400,0:RUN"LOADER.BAS"
30 BLOAD"COMPILED.BIN",R ' Run initialization code.
40 BLOAD"SAMPLE.DAT" ' Load sample data to #C000-#CFFF
50 A=USR(0) ' Play sample

In MSX tR you can generate the test sample data by writing following line:
CALL PCM REC (@&HC000,&HCFFF,3):SAVE"SAMPLE.DAT",&HC000,&HCFFF

If you don't have tR, then import the data from Amiga, PC, Mac or some 
other computer.

Let's start from easy ones...

Covox / SIMPL
-------------

Covox aka SIMPL is easy to build hardware, that is connected to printer port.
Here is routine, that plays sample using this device:

;------------------------------------

	DEFB #FE
	DEFW BEGIN
	DEFW END
	DEFW BEGIN

	ORG #D000

BEGIN:

	LD HL,PLAY
	LD (#F39A),HL
	RET

PLAY:
	DI
	LD HL,#C000	;Start address
	LD BC,#1000	;Lenght

PLAYLOOP:
	LD A,(HL)
	INC HL
	OUT (#91),A	;8-bit unsigned data to printer port.
	EXX
	LD B,60
WAIT:	DJNZ WAIT
	EXX
	DEC BC
	LD A,B
	OR C
	JP NZ,PLAYLOOP

	RET

END:
;-------------------------------------------------------------------




MSX tR PCM output
-----------------
...works same way as Covox/SIMPL so routine above can be used.
OUT (#91),A need to be changed to OUT (#A4),A


Music-Module
------------

Music-Module has 8-bit DAC as well, but it needs to be activated first. Here
is a sample routine for Music-Module:


;------------------------------------

	DEFB #FE
	DEFW BEGIN
	DEFW END
	DEFW BEGIN

	ORG #D000

BEGIN:

	LD HL,PLAY
	LD (#F39A),HL
INIT:
	LD A,#18
	OUT (#C0),A
	LD A,1
	OUT (#C1),A
	RET

PLAY:
	DI
	LD HL,#C000
	LD BC,#1000

PLAYLOOP:
	LD A,(HL)
	INC HL
	OUT (#A),A
	EXX
	LD B,60
WAIT:	DJNZ WAIT
	EXX
	DEC BC
	LD A,B
	OR C
	JP NZ,PLAYLOOP

	RET

END:

;-------------------------------------------------------------------


Key click
---------

Key click was used on many MSX1 games to play samples. As this output is only
1bit wide sound quality is bad. I suggest using PSG instead whenever it is
possible.

Key click bit is located in PPI port C, I/O port #AA/bit 7. However, in this
example we use PPI control register (I/O #AB) instead of writing the bit
manually. By changing the bit from 7 to 5 you can also use this routine to
save the sample as audio to cassette deck.

;------------------------------------

	DEFB #FE
	DEFW BEGIN
	DEFW END
	DEFW BEGIN

	ORG #D000

BEGIN:

	LD HL,PLAY
	LD (#F39A),HL
	RET

PLAY:
	DI
	LD HL,#C000
	LD BC,#1000

PLAYLOOP:
	LD A,(HL)
	INC HL

	ADD A,A
	LD A,0
	ADC A,14
	OUT (#AB),A

	EXX
	LD B,60
WAIT:	DJNZ WAIT
	EXX
	DEC BC
	LD A,B
	OR C
	JP NZ,PLAYLOOP

	RET

END:

;-------------------------------------------------------------------



MSX-Music
---------

MSX-Music has also 6bit output in each of 9 channels that can be used to play
samples. This is not anyway documented feature. I did some tests and it seems,
that #FF need to be written to OPLL test register #F (No, 9 is not enough) and
channel specific SELECT register (#20-#28) bits 1-4 should be set to 1. Also
#20 should be put to channel specific VOLINS register. (#30-#38) After this
bits 2-7 in LOWFRQ registers (#10-#18) can be used as 6bit digital output.

If you can't hear anything, execute CALL MUSIC first!

Bit 0 of SELECT register seems to be also digital output, but level is not
double compared to LOWFRQ bit7, so it can't be used as 7th bit. Because output
level is not very high, you may want to modify the routine to play on multiple
channels at a same time.

;------------------------------------

	DEFB #FE
	DEFW BEGIN
	DEFW END
	DEFW BEGIN

	ORG #D000

BEGIN:

	LD HL,PLAY
	LD (#F39A),HL
INIT:
	LD HL,#0FFF
	CALL WRFM
	LD HL,#203F
	CALL WRFM
	LD HL,#3020
	CALL WRFM
	RET

WRFM:
	LD A,H
	OUT (#7C),A
	EX (SP),HL
	EX (SP),HL
	LD A,L
	OUT (#7D),A
	EX (SP),HL
	EX (SP),HL
	RET

PLAY:
	DI
	LD HL,#C000
	LD BC,#1000
	LD A,#10
	OUT (#7C),A

PLAYLOOP:
	LD A,(HL)
	INC HL
	OUT (#7D),A
	EXX
	LD B,60
WAIT:	DJNZ WAIT
	EXX
	DEC BC
	LD A,B
	OR C
	JP NZ,PLAYLOOP

	RET

END:

;-------------------------------------------------------------------



PSG
---
PSG is available in every MSX, so it is quite a good choice for playing 
sample. In PSG sample playing need to be done following way:

Every channel frequency needs to be set to value 0. This causes frequency
generator to be switched off and sound output set to value defined by volume.
Now you can play sample by changing volume. This is anyway a bit problematic
as volume in PSG is not linear but can be calculated from formula: output
level = 2^-((15-volume)/2) 

This means that we need to find combinations that cause output level to be as
close as possible to 8bit values. Luckily Arturo Ragozini has already done
these calculations for us, so that we can use ready tables.


;------------------------------------

	DEFB #FE
	DEFW BEGIN
	DEFW END
	DEFW START

	ORG #D000

BEGIN:

	DB  00,01,02,03,04,03,05,03,04,05,06,06,05,06,06,06
	DB  06,06,07,06,07,08,08,08,07,07,09,07,09,09,08,08
	DB  09,09,08,09,09,09,09,09,10,10,10,10,09,09,10,10
	DB  10,10,09,10,11,11,11,11,11,11,11,11,10,10,10,11
	DB  11,11,11,11,11,11,11,12,11,11,12,12,11,12,11,12
	DB  12,12,12,11,12,11,12,12,12,12,11,12,12,12,12,11
	DB  12,13,12,13,11,13,13,13,13,13,13,11,13,13,13,13
	DB  13,13,13,12,13,13,13,12,12,13,12,13,13,13,13,13
	DB  13,12,13,13,13,13,13,13,13,14,13,13,14,14,14,14
	DB  14,14,13,14,14,13,14,14,14,14,14,14,13,14,14,14
	DB  14,14,14,13,14,14,13,14,14,13,13,14,14,14,14,14
	DB  14,14,14,14,13,14,14,13,14,14,14,14,14,14,13,14
	DB  14,14,15,14,15,15,15,15,15,15,15,15,15,15,15,15
	DB  14,15,15,15,15,15,15,14,15,15,15,15,15,15,15,15
	DB  15,15,15,15,15,15,15,15,15,15,15,14,15,14,14,14
	DB  14,14,15,15,14,15,15,14,15,15,15,15,15,15,15,14

	DB  00,00,00,00,00,02,00,02,02,03,01,02,04,04,03,04
	DB  04,05,04,05,05,02,03,04,06,06,01,06,02,03,06,07
	DB  05,06,07,06,06,06,07,06,04,04,05,06,08,07,06,06
	DB  07,06,08,07,03,04,03,04,04,05,05,05,08,09,09,07
	DB  07,07,08,07,08,08,08,02,08,09,03,05,09,05,08,06
	DB  06,07,06,10,07,09,08,07,08,08,09,08,08,09,08,10
	DB  09,00,08,01,10,02,03,04,04,05,06,10,06,06,06,07
	DB  06,07,07,10,08,08,07,11,11,08,11,08,09,09,09,08
	DB  09,11,09,09,10,10,10,10,10,00,10,09,02,02,04,03
	DB  04,04,11,05,05,11,07,07,07,07,07,08,10,08,08,08
	DB  08,08,09,11,09,09,12,08,09,12,11,09,10,10,09,10
	DB  10,10,10,09,11,10,10,12,10,10,11,11,11,10,12,11
	DB  11,11,00,11,01,02,03,04,03,04,04,05,05,05,06,07
	DB  12,07,07,07,08,07,08,12,08,08,08,09,08,09,09,09
	DB  08,09,09,09,09,10,10,09,10,10,10,13,09,13,13,13
	DB  13,13,10,11,13,11,10,13,11,11,11,11,11,10,10,12

	DB  00,00,00,00,00,00,00,01,01,00,00,00,01,00,02,02
	DB  03,02,01,04,01,01,01,01,03,04,00,05,01,01,04,01
	DB  01,00,04,02,03,04,01,05,01,02,01,00,02,06,03,04
	DB  01,05,06,04,00,00,02,02,03,02,03,04,06,02,03,02
	DB  03,04,00,05,02,03,04,00,05,00,02,00,03,02,07,01
	DB  02,00,04,00,03,07,00,05,02,03,08,04,05,00,06,07
	DB  03,00,07,00,08,01,01,01,02,01,00,09,02,03,04,01
	DB  05,03,04,07,01,02,06,01,02,05,04,06,02,03,04,07
	DB  05,07,06,06,00,01,02,03,04,00,05,08,00,01,00,02
	DB  02,03,00,03,04,03,00,01,02,03,04,00,09,02,03,04
	DB  04,05,00,08,02,03,00,07,05,03,09,06,00,01,07,03
	DB  04,04,05,08,10,06,06,08,07,07,00,00,01,08,09,04
	DB  05,05,00,06,00,00,00,00,02,02,03,02,03,04,03,00
	DB  01,02,03,04,00,05,02,06,04,04,05,00,06,02,03,04
	DB  07,05,05,06,06,00,01,07,03,04,04,00,08,02,03,04
	DB  04,05,07,00,06,01,08,07,04,05,05,06,06,09,09,11


START:
	LD HL,PLAY
	LD (#F39A),HL
INIT:
	LD BC,#5A0
	XOR A
INITLOOP:
	OUT (C),B
	OUT (#A1),A
	DJNZ INITLOOP
	OUT (C),A
	OUT (#A1),A
	RET

PLAY:
	LD C,#A1
	EXX
	DI
	LD HL,#C000
	LD BC,#1000

PLAYLOOP:
	LD A,(HL)
	INC HL

	EXX
	LD L,A
	LD H,#D0
	ld b,(hl)
	inc h
	ld e,(hl)
	inc h
	ld h,(hl)
	ld a,8
	out (#A0),a
	inc a
	out (c),b
	out (#A0),a
	out (c),e
	inc a
	out (#A0),a
	out (c),h

	LD B,50
WAIT:	DJNZ WAIT
	EXX
	DEC BC
	LD A,B
	OR C
	JP NZ,PLAYLOOP

	RET

END:

;-------------------------------------------------------------------



Konami SCC
----------

In Konami SCC you have theoretically three different methods to play sample.
As SCC plays actually 32 byte 8bit signed samples, first idea would be
updating the sample memory at same speed as SCC plays it. This is anyway very
hard to get right because we can not know where SCC is actually playing and we
can not reset the pointer either. Because of the hard implementation this idea
is skipped.

Second method is to use same kind of volume techniques as we used on PSG
sample playing. In SCC the volume (0-15) is linear, so tables are not needed.
To implement full 8-bit output we need at least 2 samples. One that has full
volume all the time (upper 4bits) and another sample with full volume/16
(lower 4bits). This kind of implementation can be found from example 1. 

Because SCC has signed samples, full volume is either up or down from zero
level. To go to both directions, we need 4 samples. This kind of advanced
implementation can be found from example 2. This also gives double volume
compared to 2 sample version.

One important thing to know is that change of volume is not implemented
immediately in SCC. Normally it is changed when next byte from sample memory
is played, but writing value to frequency causes current byte to be started
again. As in this example we write values very quickly to frequency registers
the internal sample counter does not actually move at all.

Third method is a variation of first method. As we don't know where SCC is
playing, let's update the whole sample memory with one and same new value.
To make sample rate not variable in low sample rates we first stop SCC from
reading sample memory. This can be done by writing value less than 9 to
frequency. Now we can update sample RAM so, that output does not change.
After sample RAM has been updated, we start SCC internal counter so that
value (where ever the counter was) is sent to output. This routine can be
found below as example 3.

Please note, that at least at time of writing this document, most (if not all)
of MSX emulators work wrong when it comes to SCC details. This may cause some
minor misbehaviour.


Example1:

;------------------------------------

SLOT:	EQU #1		;SCC Slot ID

	DEFB #FE
	DEFW BEGIN
	DEFW END
	DEFW BEGIN

	ORG #D000

BEGIN:
	LD HL,PLAY
	LD (#F39A),HL
INIT:
	LD A,SLOT
	LD H,#80
	CALL #24

	LD A,#3F	;Move to SCC page
	LD (#9000),A

	LD HL,#9800
	LD DE,#9801
	LD BC,#20
	LD (HL),128	;Max volume (=-128) sample
	LDIR
	LD C,#20
	LD (HL),248	;Max volume / 16 (=-8) sample
	LDIR

	LD HL,#FFFF	;Set low frequency for both samples
	LD (#9880),HL
	LD (#9882),HL

	LD A,3
	LD (#988F),A	;Enable channels 1&2

	RET

PLAY:
	LD HL,#FFFF
	EXX

	LD HL,#C000
	LD BC,#1000

PLAYLOOP:
	LD A,(HL)
	INC HL
	EXX
	LD D,A
	RLCA
	RLCA
	RLCA
	RLCA
	LD E,A
	LD (#988A),DE		;Volume for sample 1&2
	LD (#9881),HL		;Update frequency for sample 1&2
	LD B,55
WAIT:	DJNZ WAIT
	EXX
	DEC BC
	LD A,B
	OR C
	JP NZ,PLAYLOOP

	RET

END:
;-------------------------------------------------------------------

Example2:

;------------------------------------

SLOT:	EQU #1		;SCC Slot ID

	DEFB #FE
	DEFW BEGIN
	DEFW END
	DEFW BEGIN

	ORG #D000

BEGIN:
	LD HL,PLAY
	LD (#F39A),HL
INIT:
	LD A,SLOT
	LD H,#80
	CALL #24

	LD A,#3F
	LD (#9000),A

	LD HL,#9800
	LD DE,#9801
	LD BC,#20
	LD A,C
	LD (HL),127
	LDIR
	LD C,A
	LD (HL),8
	LDIR
	LD C,A
	LD (HL),128	;-128
	LDIR
	LD C,A
	LD (HL),248	;-8
	LDIR

	LD HL,#FFFF
	LD (#9880),HL
	LD (#9882),HL
	LD (#9884),HL
	LD (#9886),HL

	LD A,15		;Enable channels 1-4
	LD (#988F),A

	RET

PLAY:
	DI
	LD HL,#C000
	LD BC,#1000

PLAYLOOP:
	LD A,(HL)
	INC HL
	EXX
	ADD A,A
	PUSH AF
	LD H,A
	RLCA
	RLCA
	RLCA
	RLCA
	LD L,A
	LD DE,0
	POP AF
	CALL C,CFLGUP
	CALL NC,CFLGDOWN
	LD (#988A),HL
	LD (#988C),DE
	LD HL,#FFFF
	LD (#9881),HL
	LD (#9883),HL

	LD B,44
WAIT	DJNZ WAIT

	EXX
	DEC BC
	LD A,B
	OR C
	JP NZ,PLAYLOOP

	RET

CFLGDOWN:		;HL=DE : DE=-HL
	LD A,H
	CPL
	LD H,A
	LD A,L
	CPL
	LD L,A
	INC HL

	EX DE,HL
	RET

CFLGUP: 		;JUST WASTE AS MUCH TIME AS CFLDOWN ROUTINE DOES
	LD A,A
	LD A,A
	LD A,A
	LD A,A
	EX AF,AF'
	INC BC
	CPL
	SCF
	RET
END:

;-------------------------------------------------------------------

Example3:

;------------------------------------


SLOT:	EQU #1		;SCC Slot ID

	DEFB #FE
	DEFW BEGIN
	DEFW END
	DEFW BEGIN

	ORG #D000

BEGIN:

	LD HL,PLAY
	LD (#F39A),HL
INIT:
	LD A,SLOT
	LD H,#80
	CALL #24

	LD A,#3F
	LD (#9000),A

	LD HL,0
	LD (#9880),HL

	LD A,15
	LD (#988A),A

	LD A,1
	LD (#988F),A
	RET


PLAY:
	DI
	LD	HL,#9881
	LD	DE,0C000H
	LD	BC,1000H
PLAYLOOP:
	LD	A,(DE)
	XOR	128		; Convert to signed data
	INC	DE
	LD	(HL),0		; Stop output update
	EXX
	LD	HL,9800H
	LD	DE,9801H
	LD	(HL),A

	LDI			; 32 x LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI
	LDI

	LD B,16
WAIT:	DJNZ WAIT

	EXX
	LD	(HL),#FF	;Update output
	DEC	BC
	LD	A,B
	OR	C
	JP	NZ,PLAYLOOP
	RET

END:

;-------------------------------------------------------------------


Few words about sample timing...
--------------------------------

All these examples have been timed using CPU. This is ok as long as we work
with non over clocked computers and we don't want to multitask. If this kind
of activity is required then external timer is a good idea. External timer is
 also quite a big help when we want to play notes on samples.

Standard MSX1 is worst case scenario as it usually does not have anything that
 you could use for sample timing. Only timer available is 50/60Hz VDP
interrupt, that is awfully too slow for sample purposes.

In MSX2 VDP's Horizontal Retrace Flag in status register 2 can be used to get
about 15.6KHz frequency. This can be very useful especially if you are
planning to do VDP tricks at a same time you play sample.

If you are not afraid of extreme tricks you may also use MSX2 real time clock
for sample timing. This means, that you first need to detect/set VDP 50/60HZ
mode. Then make a fast custom interrupt routine that calculates real time
using VDP interrupts. Then you need to synchronize Real-time clock time to
VDP clock and set RTC to test mode by using RTC register #E. This way you
can get 16 KHz timer. After playing sample, you need to restore RTC and
synchronize time back to it as users really don't like to get their clock
messed up!

MSX tR has sample timer located at I/O ports. #E6 & #E7 In MSX tR A1GT you
can use also MIDI interrupts to play sample.

Many external devices like Music-Module, RS-232 interfaces, Disk drive
interfaces, MIDI interfaces etc. have also different kind of timers. If you
require such interface, you might want to use these timers as well. Best
timers can also generate interrupts so, that you can do sample playing at
background.

~NYYRIKKI

By ro

Guardian (4185)

ro's picture

09-09-2005, 19:42

nifty !

By SolidEric

Champion (332)

SolidEric's picture

09-09-2005, 20:42

Is it possible to play mod-files on psg/music-module/fmpac or scc? I know it can for moonsound and turbo-r

By Manuel

Ascended (16843)

Manuel's picture

09-09-2005, 21:32

he ro, can you send me an e-mail on manuel AT msxnet DOT org?

By NYYRIKKI

Enlighted (5588)

NYYRIKKI's picture

09-09-2005, 22:13

For MOD-files you need MoonSound OR tR. I don't remember the name for MSX2+MoonSound program, but for MSX tR there is MOD-player and MOD-editor made by Xelasoft.

CPU power is not enough to play reasonable sound quality on standard MSX2 without hardware acceleration. I have anyway wrote a MOD-player for MSX1 (that is more like a joke) :

http://www.msx.org/MOD-player-for-MSX1.newspost2174.html

Page 2/4
1 | | 3 | 4