PCM player using SCC

Страница 22/33
15 | 16 | 17 | 18 | 19 | 20 | 21 | | 23 | 24 | 25 | 26 | 27

By Manuel

Ascended (19273)

Аватар пользователя Manuel

25-10-2007, 00:55

manuel, can you describe that a bit more detailed. Did the change that broke Manuel's demo also make the sound less good in other cases? If so did you figure out what you did?

There have been loads and loads of sound changes since openMSX 0.6.2 got released. So I have no idea which one made the sound quality change so much. In 0.6.2 the sound is a bit harsh and has high volume peaks. In 0.6.3 it is softer and smoother, like the real MSX.

By dvik

Prophet (2200)

Аватар пользователя dvik

25-10-2007, 01:07

Here is the code. The sample data needs to be interleaved the following way:

32 bytes ch1
32 bytes ch2
32 bytes ch3
32 bytes ch4
32 bytes ch1
...

One thing I haven't tested yet is if writing only one byte in the period
register resets the phase. This code assumes that writing the high
byte resets the phase.
Its very easy to change to write the low byte and fairly easy to write
the whole period if needed. Tests on real SCC will tell...

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


        fname "sccplay.rom"
        ;output "sccplay.rom"
        
        org 4000h
        dw  4241h,START,0,0,0,0,0,0


Bank1:  equ      05000h
Bank2:  equ      07000h
Bank3:  equ      09000h
Bank4:  equ      0B000h

;; 7648Hz in 60Hz mode
Period: equ      1873

;-------------------------------------
; Entry point
;-------------------------------------
START:
        call    powerup
        xor     a
        call    005Fh

        di
        
        ld      a,3Fh
        LD      (Bank3),A

        call    SccInit
        
        call    ReplayerInit

        call    InstallIntHanlder
        
        ei
        
.halt:  jp      .halt

        ret
        
        
InstallIntHanlder:
        di
        ld      a,195
        ld      hl,HandleInt
        ld      ($FD9A),a
        ld      ($FD9B),hl
        ret
        
;-------------------------------------
;-------------------------------------
HandleInt:
        push    af
        push    bc
        push    de
        push    hl
        
        call    ReplayerUpdate
        
        pop     hl
        pop     de
        pop     bc
        pop     af
        ret        
        
;-------------------------------------
; Initialize the scc
;-------------------------------------
SccInit:
        ld  a,00100000b         ; Reset phase when freq is written
        ld  (98E0h),a
        
        ld      a,15
        ld      (988Ah),a       ; volume ch1
        ld      (988Bh),a       ; volume ch2
        ld      (988Ch),a       ; volume ch3
        ld      (988Dh),a       ; volume ch4
        xor     a
        ld      (988Eh),a       ; volume ch5

        ld      a,00011111b     ; all channels active
        ld      (988Fh),a

        ld      hl,Period
        ld      (9880h),hl
        ld      (9882h),hl
        ld      (9884h),hl
        ld      (9886h),hl
        
        ret  


;-------------------------------------
; Initialize replayer
;-------------------------------------
ReplayerInit:
        ld      hl,6000h
        ld      (SamplePos),hl
        ld      a,1
        ld      (SamplePage),a
        ld      (Bank2),a
        ret
        

;-------------------------------------
; Moves sample pointer to next page
;-------------------------------------
ReplayerNextPage:
        ld      hl,6000h
        push    af
        ld      a,(SamplePage)
        cp      (SAMPLE_END - SAMPLE_START + 1FFFh)/2000h
        jr      nz,.norewind
        xor     a
.norewind:
        inc     a
        ld      (SamplePage),a
        ld      (Bank2),a
        pop     af
        ret
        

;-------------------------------------
; Updates the SCC wave table. 
;-------------------------------------
ReplayerUpdate:
        ld      hl,(SamplePos)
        ld      a,7
        
        ;468
        
        ld      de,9800h        ; 11
        ld      bc,18           ; 11
        ldir                    ; 23*18-5
        ld      bc,14           ; 11
        add     hl,bc           ; 12
        ld      (9881h),a       ; 14
        
        ld      de,9820h        ; 11
        ld      bc,18           ; 11
        ldir                    ; 23*18-5
        ld      bc,14           ; 11
        add     hl,bc           ; 12
        ld      (9883h),a       ; 14
        
        ld      de,9840h        ; 11
        ld      bc,18           ; 11
        ldir                    ; 23*18-5
        ld      bc,14           ; 11
        add     hl,bc           ; 12
        ld      (9885h),a       ; 14
        
        ld      de,9860h        ; 11
        ld      bc,18           ; 11
        ldir                    ; 23*18-5
        ld      bc,14           ; 11
        add     hl,bc           ; 12
        ld      (9887h),a       ; 14
        
        ; Start over with rest of samples
        
        ld      bc,10000h-128+16
        add     hl,bc
        ld      bc,16
        
        ld      de,9810h
        ldir
        ld      bc,16
        add     hl,bc
        
        ld      de,9830h
        ldir
        ld      bc,16
        add     hl,bc
        
        ld      de,9850h
        ldir
        ld      bc,16
        add     hl,bc
        
        ld      de,9870h
        ldir
        
        bit     7,h
        call    nz,ReplayerNextPage
        
        ld      (SamplePos),hl
        
        ret


;-------------------------------------
;   Powerup routine for non-Z180 code.
;   set pages and subslot
;-------------------------------------
powerup:
        call    0x138
        rrca
        rrca
        and     0x03
        ld      c,a
        ld      b,0
        ld      hl,0xfcc1
        add     hl,bc
        or      (hl)
        ld      b,a
        inc     hl
        inc     hl
        inc     hl
        inc     hl
        ld      a,(hl)
        and     0x0c
        or      b

        ld      h,0x80
        call    0x24

        ret

        
;-------------------------------------
; To make rom guesseres happy
;-------------------------------------
dummy:
        xor     a
        ld      (Bank1),a
        ld      (Bank3),a
        ld      (Bank1),a
        ld      (Bank3),a
        ret

;-------------------------------------
; Padding for rom player
;-------------------------------------
ds	$6000 - $
     


;-------------------------------------
; Sample data
;-------------------------------------
SAMPLE_START:
incbin "fth01.bin",0,(56+64+128+256)*1024
SAMPLE_END:


;-------------------------------------
; Padding, align rom image to a power of two.
;-------------------------------------

SAMPLE_LENGTH:  equ SAMPLE_END - SAMPLE_START

        IF (SAMPLE_LENGTH <= 6000h)
        DS (6000h - SAMPLE_LENGTH)
        ELSE
        IF (SAMPLE_LENGTH <= 10000h-2000h)
        DS (E000h - SAMPLE_LENGTH)
        ELSE
        IF (SAMPLE_LENGTH <= 1E000h)
        DS (1E000h - SAMPLE_LENGTH)
        ELSE
        IF (SAMPLE_LENGTH <= 3E000h)
        DS (3E000h - SAMPLE_LENGTH)
        ELSE
        IF (SAMPLE_LENGTH <= 7E000h)
        DS (7E000h - SAMPLE_LENGTH)
        ELSE
        DS (FE000h - SAMPLE_LENGTH)
        ENDIF
        ENDIF
        ENDIF
        ENDIF
        ENDIF



FINISH:


;---------------------------------------------------------
; Variables
;---------------------------------------------------------
VarBase:            equ $e000

SamplePos:          equ VarBase + 0
SamplePage:         equ VarBase + 2

By dvik

Prophet (2200)

Аватар пользователя dvik

25-10-2007, 01:24

I tested on a real MSX and the result is ok but not great. There are some clicks and its clearly some phase problems. Perhaps the two are related.

I'll see if setting the period differently may help.

By Manuel

Ascended (19273)

Аватар пользователя Manuel

25-10-2007, 01:37

What is actually better/different than that fifth.rom? That one sounded really good on a real MSX... (it sounded a bit distorted on openMSX, but we haven't found out why yet.)

By dvik

Prophet (2200)

Аватар пользователя dvik

25-10-2007, 01:48

fifth.rom uses one channel for playing samples and one rotated channel for synchronization. That one is also fully syncrhonized to avoid access to the SCC while its playing some samples that cause bus conflicts or something.

This new one has a very nice algorithm that requires updates only in VBLANK to play 7.6kHz samples. But its using all SCC channels with phase shift do make the sample frequency 4x the actual replayed frequency.

From a gaming perspective the last version is a lot better because its not using much cpu at all, less than 4% of the cpu (!)

fifth.rom replays 22kHz samples and uses around 25% cpu and it requires more complicated synchronization but with much better result.

By dvik

Prophet (2200)

Аватар пользователя dvik

25-10-2007, 07:28

it sounded a bit distorted on openMSX
In 0.6.2 it sounds very funny. Is it better in 0.6.3?

By ARTRAG

Enlighted (6923)

Аватар пользователя ARTRAG

25-10-2007, 08:43

Questions:

why 7648Hz and not 4*60*32 ?
Could this be the problem ?
If the freqs in SCC and in the VDP does not match exactly you could miss some samples or hear jitter on samples at each VINT
do you mean with this that the VDP framerate is a bit lower than 60Hz ?

Why all the push/pop in HandleInt ?
At that point bios have already saved all the registers,
maybe it has already done something that jitter the timing...

One point
using lineint you can double or more the Fs....

By dvik

Prophet (2200)

Аватар пользователя dvik

25-10-2007, 08:59

The frequency isn't exactly 60Hz ( its 3579545/(262*228) ). But I thought that was the problem too so I did an adaptive method that calculates the correct period using rotation mode and the result is still the same. I also tried to make my own int handler and still not any better results.

The pops and pushes are because its saving all registers, its mainly if you have your own int handler but thats not an issue either.

I also thought about the line int. One line int would give quite good sample frequency and still using less then 8% of the CPU. Its too bad that that SCC isn't as good as it should be....

By ARTRAG

Enlighted (6923)

Аватар пользователя ARTRAG

25-10-2007, 09:59

Daniel,
In your code you update 32+2 samples per channel per frame
I think I understand the reasons, and I think what you do is correct:
the problem is that the SCC goes on with the play while you're updating
tables, and when you end to the second pass of updates, SCC has moved
on of 2 samples in the new data

but in this way, in the end, you pass to the scc 34*4 samples per frame, so
the actual FS should be 34*4*59,9227434 = 8149,49Hz and not less!!

moreover, I see that you reset the SCC at the end of the first update loop (that lasts one sample)

        ld      de,9800h        ; 11
        ld      bc,18           ; 11
        ldir                    ; 23*18-5
        ld      bc,14           ; 11
        add     hl,bc           ; 12
        ld      (9881h),a       ; 14                 <-----

why not updating one byte only, reset the scc, continue updating fot the last of one sample, and than move to the rest ?

        ld      de,9800h        ; 11
        ldi
        ld      (9881h),a       ; 14                 <-----
        ld      bc,new_count           ; 11
        ldir                    

this allows the SCC to start playing the new sample immediately and in theory to not play the old sample at position #0

moreover, just and idea, you can interleave the channel data in rom in order to avoid
all the adjustments :

        ld      bc,14           ; 11
        add     hl,bc           ; 12

As you need to preprocess the input in any case, this whouldn't be a problem.

By Manuel

Ascended (19273)

Аватар пользователя Manuel

25-10-2007, 12:49

it sounded a bit distorted on openMSX
In 0.6.2 it sounds very funny. Is it better in 0.6.3?

It has the same distortions. It's just that the sound is less harsh in 0.6.3, similar to the other improvement I mentioned.

Страница 22/33
15 | 16 | 17 | 18 | 19 | 20 | 21 | | 23 | 24 | 25 | 26 | 27