What the PSG also can sound like...

페이지 3/7
1 | 2 | | 4 | 5 | 6 | 7

By ToriHino

Champion (361)

ToriHino의 아바타

21-06-2017, 19:43

Here is some more information about the SID player on the ZX-Spectrum. It does not play directly a sid file (Like NYYRIKKI's sidplay or RoboSID) but a converted preprocessed file (.m64).

https://www.worldofspectrum.org/forums/discussion/54160/c64-sid-player-coming-soon-to-specy-128

Apparently only the 50hz timer is used:

Quote:

Only AY will be used, and the quality is worse, because on Speccy we are not able to set 10KHz interrupt, so the 50Hz control interrupt stops the digi playback for 1,6% of CPU time (5 raster line)

By Hrothgar

Champion (479)

Hrothgar의 아바타

21-06-2017, 20:10

syn wrote:

https://youtu.be/Zr1r6FSrsz4 sid emulation on the ZX-spectrum! This is how it would sound like on msx z80.

Why would you try and play Sid's "Auf Wiedersehen Monty" in this way? It's one of those compositions where I'd unequivocally say the original PSG version beats the SID one.

By Grauw

Ascended (8397)

Grauw의 아바타

21-06-2017, 20:33

Now that you mention it, in Auf Wiedersehen Monty you can also clearly hear that they not only implemented PWM (often called “the SID effect” on Atari ST) but also triangle waves… that’s pretty nice, I haven’t heard that before in ST music I think.

By Hrothgar

Champion (479)

Hrothgar의 아바타

21-06-2017, 21:37

Various Gremlin tunes are among my favourites. Monty, but also Masters of the Universe.

IMHO when trying to achieve a less bland and standard sound from PSG, one could try to use the techniques Gremlin used. While the SID really excels in making various sound effects possible, most composers completely overdo and abuse it, "just because they can". It's like giving a toddler a hammer: suddenly everything looks like a nail to it... Gremlin on PSG achieved a good combination of the PSG's utter clarity of sound with the occasional extra touch.

8 bit comparison: https://www.youtube.com/watch?v=aASy40TjJto For MSX, listen to the ZX version. They're identical, but in this video the MSX version was recorded at way too low volume and playing 20% too fast :-|

By Grauw

Ascended (8397)

Grauw의 아바타

21-06-2017, 21:53

One of my favourites is the Double Dragon 2 theme. Uff, that PSG, beautiful.

(Sorry, off-topic :D)

(Slightly more on-topic, MSX version of Auf Wiedersehen Monty with correct speed is here @ 6:18.)

By Hrothgar

Champion (479)

Hrothgar의 아바타

21-06-2017, 21:54

As the topic's title is "what the PSG also can sound like", I don't see why it's off-topic.
Sarcastic at best.

By Grauw

Ascended (8397)

Grauw의 아바타

21-06-2017, 22:32

On the subject of Gremlin, let’s not forget Death Wish III and Venom Strikes Back Smile.

But anyway, back to “what the PSG can also sound like” as-in-unexpectedly, actually a pretty easy and little CPU-consuming (and underused) technique is to use audio-rate frequencies for the envelope generator! This way you can get nice buzzy sounds like in Six Miles High and Raccoonerie by Gasman from AY Riders.

By NYYRIKKI

Enlighted (5366)

NYYRIKKI의 아바타

22-06-2017, 13:35

Grauw wrote:

I once did an experiment with a "SID effect" on MSX using synchronous CPU timing, that worked pretty nicely, not noisy. But it was a simplified case, I can imagine keeping three-channel variable frequency playback in sync is much harder, that may introduce the noise. That experiment made me find a bug in openMSX too btw :D. (code snippet at that link)

I've heard about this few times over the years, but I newer quite got the idea... What is the idea of adjusting volume in sync with PSG compared to adjusting the volume without PSG tone? Can you explain the idea in more detail or is there some explanation you can link to?

By Grauw

Ascended (8397)

Grauw의 아바타

22-06-2017, 14:30

What is called the "SID effect" simply refers to pulse waves with variable duty cycle (either static or modulated over time).

The PSG produces square waves by outputting 1 for a period of n clock ticks (/16), and then outputting 0 for another n clock ticks (/16). The output of 1 is also modulated by the volume setting.

The more general case of square waves is pulse waves, which specify the 1 period relative to the 0 period as the duty cycle. For square waves, because the 1 and 0 periods are the same, the duty cycle is 50%.

So the goal is to make the PSG generate a pulse waveform with duty cycles < 50%. This can be achieved by prematurely cutting off the 1 output using the volume register.

For example, when playing a tone with period 100, the PSG will output a 1 for 1600 cycles and a 0 for another 1600 cycles. Now if you let the CPU control the volume synchronously, setting volume to 15 initially, wait 800 cycles, set volume 0, wait 2400 cycles, set volume back to 15, and repeat. Then the actual waveform that is produced will be a pulse wave with 25% duty cycle.

As a slight simplification, because the volume can be turned back on anywhere within the latter 1600 cycles (the output will remain 0 either way), you can actually modulate the volume at the exact same rate as the PSG does, and the initial time delay will determine the pulse width. E.g. initially wait 800 cycles, set volume 0, wait 1600 cycles, set volume 15, wait 1600 cycles, set volume 0, etc. will produce the very same 25% duty cycle.

The difficulty here is that as the tone frequencies change, the CPU needs to cut the volume at different rates as well. If you add support for 3 channels and pulse width modulation, it further complicates matters.

For the Atari ST this is relatively easy to do because it has DMA whose rate can be controlled by a timer (at least I think so). For MSX, quite a bit more complicated.

Perhaps the easiest way is to use a high frequency timer interrupt and decrement counters for all three channels, every time they cross 0 you toggle the volume and re-add the tone frequency to the counter. The duty cycle will be a bit jittery, but if the update frequency is high enough it’ll probably sound ok.

Note that duty cycles > 50% don’t need to be supported, because a pulse wave with duty cycle 80% sounds identical to one with duty cycle 20%, except that the waveform is inversed.

By Grauw

Ascended (8397)

Grauw의 아바타

22-06-2017, 15:39

Grauw wrote:

Perhaps the easiest way is to use a high frequency timer interrupt and decrement counters for all three channels, every time they cross 0 you toggle the volume and re-add the tone frequency to the counter. The duty cycle will be a bit jittery, but if the update frequency is high enough it’ll probably sound ok.

Some untested example code to illustrate the concept:

Channel: MACRO ?number
	number:
		db ?number
	period:
		dw 0
	periodOffset:
		dw 0
	periodCounter:
		dw 0
	volume:
		db 0
	currentVolume:
		db 0
	newNote:
		db 0
	ENDM

; a = volume
; bc = period
; de = period offset
; ix = this
Channel_PlayNote:
	ld (ix + Channel.period),c
	ld (ix + Channel.period + 1),b
	ld (ix + Channel.periodOffset),e
	ld (ix + Channel.periodOffset + 1),d
	ld (ix + Channel.volume),a
	set 0,(ix + Channel.newNote)
	ret

; ix = this
Channel_Interrupt1000Hz:
	bit 0,(ix + Channel.newNote)
	call nz,Channel_InterruptNewNote
	ld l,(ix + Channel.periodCounter)
	ld h,(ix + Channel.periodCounter + 1)
	ld de,-(3579545 / 16 / 1000)
	add hl,de
	call nc,Channel_ToggleVolume
	ld (ix + Channel.periodCounter),l
	ld (ix + Channel.periodCounter + 1),h
	ld a,(ix + Channel.currentVolume)
	ld e,(ix + Channel.number)
	call PSG_SetVolume
	ret

; ix = this
Channel_InterruptNewNote:
	ld e,(ix + Channel.periodOffset)
	ld d,(ix + Channel.periodOffset + 1)
	ld (ix + Channel.period),e
	ld (ix + Channel.period + 1),d
	ld bc,0                         ; sync PSG with CPU
	ld e,(ix + Channel.number)      ; not sure this works, experiment
	call PSG_SetFrequency
	ld c,(ix + Channel.period)
	ld b,(ix + Channel.period + 1)
	call PSG_SetFrequency
	ld (ix + Channel.periodCounter),0
	ld (ix + Channel.periodCounter + 1),0
	ld (ix + Channel.currentVolume),0
	res 0,(ix + Channel.newNote)
	ret

; ix = this
Channel_ToggleVolume:
	ld a,(ix + Channel.currentVolume)
	and a
	jr z,Channel_SetVolume
	jr Channel_ResetVolume

; ix = this
Channel_SetVolume:
	ld a,(ix + Channel.volume)
	ld (ix + Channel.currentVolume),a
	ret

; ix = this
Channel_ResetVolume:
	ld (ix + Channel.currentVolume),0
	ret

;
Channel_channel1:
	Channel 0
Channel_channel2:
	Channel 1
Channel_channel3:
	Channel 2
페이지 3/7
1 | 2 | | 4 | 5 | 6 | 7