;			VOICE CHANGER
;
;		call from F-BASIC386 or High C
;	callm address,varptr(source),varptr(new),varptr(param),varptr(work)
;	void  VCHAN(*sourcesnd,*newsnd,*param,*work)
;
;
;			1990 3  Hiroshi TODA
;
;			1993 12 High C 用に改造
;
;	param: cycle , mode*10000H
;	work area = 256Byte
;
;

	.386p


param	struc

	dd	?
	dd	?
source	dd	?		; source snd.data address
new	dd	?		; new snd.data address
paradd	dd	?		; param. address
wadd	dd	? 		; work address

param   ends

work	struc

;data area

cycle	dd	?		; cycle
mode	dd	?		; rate

;work area

point	dd	?		; ov.sampling point (decimal)
	dd	?		; ov.sampling point (integer)
rate	dd	?		; add (decimal)
	dd	?		; add (integer)
rend	dd	?		; read end

rated	dd	?		; add rate
ratea	dd	?		; add buf.
pbuf	dd	?		; point buf. (decimal)
	dd	?		; point buf. (integer)
count1	dd	?		; cycle count
count2	dd	?		; cycle*10000H

work	ends

cseg	segment	dword public use32 'CODE'
	assume	cs:cseg,ds:cseg

	public	sndVoiceChange
	db	'sndVoiceGhange',14
sndVoiceChange	proc	near
	push	ebp
	mov	ebp,esp
	push	esi
	push	edi
	push	ebx

	mov	esi,[ebp].wadd		; esi <-- work area top add
	mov	ecx,[ebp].paradd	; ecx <-- para. add.
	xor	edx,edx			; edx=count
main01:	mov	eax,[ecx][edx*4]	; para. --> work area
	mov	[esi][edx*4],eax
	inc	edx
	cmp	edx,2
	jb	main01

	mov	ebx,[ebp].source	; ebx <-- source snd. add.
	mov	edi,[ebp].new		; edi <-- new snd. add.
	xor	edx,edx			; head trans
main02:	mov	eax,[ebx][edx*4]
	mov	[edi][edx*4],eax
	inc	edx
	cmp	edx,8
	jb	main02

	mov	ecx,[ebx+12]		; ecx <-- length
	mov	[esi].rend,ecx
	cmp	ecx,0
	je	mainE
	add	ebx,32			; add head(32Byte)
	add	edi,32
	add	[esi].rend,ebx
	sub	[esi].rend,1

	mov	eax,[esi].cycle		; count set
	cmp	eax,0
	jne	main00
	mov	eax,1
	mov	[esi].cycle,eax
main00:	mov	[esi].count1,eax
	xor	edx,edx			; set data
	mov	[esi].point,edx
	mov	[esi].ratea,edx
	mov	eax,[esi].mode
	shld	edx,eax,16
	shl	eax,16
	mov	[esi].rate,eax
	mov	[esi].rate+4,edx
	cmp	edx,0
	je	main03
	mov	eax,[esi].mode		; hi
	sub	eax,10000H
	mov	[esi].rated,eax
	mov	eax,[esi].cycle		; set count2
	shl	eax,16
	mov	[esi].count2,eax
	jmp	main04
main03:	mov	eax,10000H
	sub	eax,[esi].mode
	mov	[esi].rated,eax
	mov	eax,10000H		; set count2
	sub	eax,[esi].rated
	mul	dword ptr [esi].cycle
	mov	[esi].count2,eax

main04:	mov	al,[ebx]		; trans while zero
	mov	[edi],al
	inc	ebx
	inc	edi
	dec	ecx
	je	mainE
	and	al,7fH
	je	main04
	dec	ebx
	dec	edi
	inc	ecx
	mov	[esi].point+4,ebx
	xor	eax,eax
	add	eax,dword ptr [esi].rate+4
	je	main05
	call	hi
	jmp	mainE
main05:	call	lw

mainE:
	pop	ebx
	pop	edi
	pop	esi
	mov	esp,ebp
	pop	ebp
	ret


hi:	lea	eax,[esi].point
	call	smp			; ov.smp.
	call	wr			; write
	dec	ecx
	je	hiE

;	mov	ax,[edi-2]		; cross check
;	cmp	ax,8080H
;	je	hi00
;	and	eax,8080H
;	cmp	eax,80H

	call	close_ck

	jne	hi03
hi00:	mov	eax,[esi].rated		; ratea=ratea+rated
	add	[esi].ratea,eax
hi01:	mov	eax,[esi].ratea
	cmp	eax,[esi].count2
	jb	hi03
	sub	eax,[esi].count2	; make wave
	mov	[esi].ratea,eax
	mov	eax,[esi].point		; point -> buf.
	mov	edx,[esi].point+4
	mov	[esi].pbuf,eax
	mov	[esi].pbuf+4,edx
	mov	eax,[esi].cycle		; set cycle count
	mov	[esi].count1,eax
hi02:	call	adp			; loop start
	lea	eax,[esi].point
	call	smp
	call	wr
	dec	ecx
	je	hiE

;	mov	ax,[edi-2]
;	cmp	ax,8080H
;	je	hi0A
;	and	eax,8080H
;	cmp	eax,80H

	call	close_ck

	jne	hi02			; loop end
hi0A:	dec	dword ptr [esi].count1	; cycle count
	jne	hi02
	mov	eax,[esi].pbuf		; buf. -> point
	mov	edx,[esi].pbuf+4
	mov	[esi].point,eax
	mov	[esi].point+4,edx
	dec	edi			; 1Byte over write

	; 継ぎ接ぎを滑らかにする 1994 1

	dec edi
	call	red_m_o
	sar		eax,2	; 読んだデータを1/4に
	call	wr		; 半分にして書き直し( ここで inc edi してる)

	lea	eax,[esi].point
	call	smp
	sar		eax,2	; 1/4に
	call	wr

	jmp	hi01
hi03:	call	adp
	jmp	hi
hiE:	ret

lw:	lea	eax,[esi].point
	call	smp			; ov.smp.
	call	wr			; write
	dec	ecx
	je	lwE

;	mov	ax,[edi-2]		; cross check
;	cmp	ax,8080H
;	je	lw00
;	and	eax,8080H
;	cmp	eax,80H

	call	close_ck

	jne	lw03
lw00:	mov	eax,[esi].rated		; ratea=ratea+rated
	add	[esi].ratea,eax
lw01:	mov	eax,[esi].ratea
	cmp	eax,[esi].count2
	jb	lw03
	sub	eax,[esi].count2	; delete wave
	mov	[esi].ratea,eax
	mov	[esi].pbuf,ecx		; count(ecx,edi) -> buf.
	mov	[esi].pbuf+4,edi
	mov	eax,[esi].cycle		; set cycle count
	mov	[esi].count1,eax
lw02:	call	adp			; loop start
	lea	eax,[esi].point
	call	smp
	call	wr
	dec	ecx
	je	lwE

;	mov	ax,[edi-2]
;	cmp	ax,8080H
;	je	lw0A
;	and	eax,8080H
;	cmp	eax,80H

	call	close_ck

	jne	lw02			; loop end
lw0A:	dec	dword ptr [esi].count1	; cycle count
	jne	lw02
	mov	ecx,[esi].pbuf		; buf. -> count(ecx,edi)
	mov	edi,[esi].pbuf+4
	dec	edi			; 1Byte over write

	; 継ぎ接ぎを滑らかにする 1994 1

	dec edi
	call	red_m_o
	sar		eax,2	; 読んだデータを1/4に
	call	wr		; 半分にして書き直し( ここで inc edi してる)

	lea	eax,[esi].point
	call	smp
	sar		eax,2	; 1/4に
	call	wr

	jmp	lw01
lw03:	call	adp
	jmp	lw
lwE:	ret


; 出来上がったデータを読む

red_m_o:	mov	al,[edi-1]		; read
	and	eax,0ffH
	cmp	eax,128
	jb	red01
	mov	edx,eax
	mov	eax,128
	sub	eax,edx
red01:	ret

;	edi-4を境にクロスしてるかをフィルタ(平均化)にかけて判断
;	eax = 0ならクロス, eax != 0ならノンクロス

close_ck:
	push	ecx
	push	edx

;	mov		eax,[edi-8]
	mov		edx,[esi].(point+4)		; オリジナルのデータを見るように変更
	mov		eax,[edx-2]

	shld	edx,eax,8
	cmp		dl,80h
	jb		cls00
	mov		dh,dl
	mov		dl,80h
	sub		dl,dh
cls00:
	movsx	edx,dl
	mov		ecx,edx

	shld	edx,eax,16
	cmp		dl,80h
	jb		cls01
	mov		dh,dl
	mov		dl,80h
	sub		dl,dh
cls01:
	movsx	edx,dl
;	shl		edx,2
	add		ecx,edx

	shld	edx,eax,24
	cmp		dl,80h
	jb		cls02
	mov		dh,dl
	mov		dl,80h
	sub		dl,dh
cls02:
	movsx	edx,dl
;	shl		edx,2
	add		ecx,edx

	shld	edx,eax,32
	cmp		dl,80h
	jb		cls03
	mov		dh,dl
	mov		dl,80h
	sub		dl,dh
cls03:
	movsx	edx,dl
	add		ecx,edx

	cmp		ecx,0
	jg		cls_no

;	mov		eax,[edi-4]
	mov		edx,[esi].(point+4)		; オリジナルのデータを見るように変更
	mov		eax,[edx-1]

	shld	edx,eax,8
	cmp		dl,80h
	jb		cls10
	mov		dh,dl
	mov		dl,80h
	sub		dl,dh
cls10:
	movsx	edx,dl
	mov		ecx,edx

	shld	edx,eax,16
	cmp		dl,80h
	jb		cls11
	mov		dh,dl
	mov		dl,80h
	sub		dl,dh
cls11:
	movsx	edx,dl
;	shl		edx,2
	add		ecx,edx

	shld	edx,eax,24
	cmp		dl,80h
	jb		cls12
	mov		dh,dl
	mov		dl,80h
	sub		dl,dh
cls12:
	movsx	edx,dl
;	shl		edx,2
	add		ecx,edx

	shld	edx,eax,32
	cmp		dl,80h
	jb		cls13
	mov		dh,dl
	mov		dl,80h
	sub		dl,dh
cls13:
	movsx	edx,dl
	add		ecx,edx

	cmp		ecx,0
	jl		cls_no

	xor		eax,eax
	jmp		cls_end

cls_no:
	xor		eax,eax
	sub		eax,1

cls_end:
	pop		edx
	pop		ecx
	ret


;	POINT=POINT+RATE

adp:	push	eax
	push	edx
	mov	eax,[esi].point
	mov	edx,[esi].point+4
	add	eax,[esi].rate
	adc	edx,[esi].rate+4
	cmp	edx,[esi].rend
	jb	adp01
	xor	eax,eax
	mov	edx,[esi].rend
adp01:	mov	[esi].point,eax
	mov	[esi].point+4,edx
	pop	edx
	pop	eax
	ret

;	WRITE DATA
;	eax -> pcm data -> [edi] & inc edi

wr:	cmp	eax,0			; write
	js	wr01
	je	wr01
	cmp	eax,128			; +
	jb	wr02
	mov	eax,127
	jmp	wr02
wr01:	mov	edx,eax			; -
	mov	eax,128
	sub	eax,edx
	cmp	eax,256-1	; data255はloopStopの意味があるから除外 1993 12
	jb	wr02
	mov	eax,255-1	; data255はloopStopの意味があるから除外 1993 12
wr02:	mov	[edi],al
	inc	edi
	ret

;	OVER SAMPLING for PCM DATA(8bit)
;input	eax = 64bit(32bit/decimal,32bit/integer) data address(ds:)
;output	eax = over sampring data ( 32bit sign (-128 -- +127) )

smp:	push	ebx
	push	ecx
	push	edx
	push	esi
	push	edi
	mov	ebx,[eax]		; ebx = decimal
	mov	esi,[eax+4]		; esi = integer
	shr	ebx,24			; ebx --> 8bit
	jne	smp00

	mov	al,[esi]		; decimal=0
	and	eax,0ffH
	cmp	eax,128
	jb	smp0A
	mov	edx,eax
	mov	eax,128
	sub	eax,edx
smp0A:	jmp	smp06

smp00:
	mov	eax,[esi-1]		; 周囲がみな無信号ならノイズを出さないよう直接0を返す
	cmp	eax,80808080h
	jne	smp0B
	xor	eax,eax
	jmp	smp06

smp0B:
	call	smp01
smp01:	pop	edi
	add	edi,smptb-smp01		; edi = table point

	mov	al,[esi]
	and	eax,0ffH
	cmp	eax,128
	jb	smp02
	mov	edx,eax
	mov	eax,128
	sub	eax,edx
smp02:	add	eax,128
	mul	byte ptr cs:[edi][ebx]
	mov	ecx,eax

	mov	al,[esi-1]
	and	eax,0ffH
	cmp	eax,128
	jb	smp03
	mov	edx,eax
	mov	eax,128
	sub	eax,edx
smp03:	add	eax,128
	mul	byte ptr cs:[edi][ebx+256]
	sub	ecx,eax

	mov	eax,ebx			; ebx = 256 - ebx
	mov	ebx,256
	sub	ebx,eax

	mov	al,[esi+1]
	and	eax,0ffH
	cmp	eax,128
	jb	smp04
	mov	edx,eax
	mov	eax,128
	sub	eax,edx
smp04:	add	eax,128
	mul	byte ptr cs:[edi][ebx]
	add	ecx,eax

	mov	al,[esi+2]
	and	eax,0ffH
	cmp	eax,128
	jb	smp05
	mov	edx,eax
	mov	eax,128
	sub	eax,edx
smp05:	add	eax,128
	mul	byte ptr cs:[edi][ebx+256]
	sub	ecx,eax
	sub	ecx,128*256
	sar	ecx,8
	mov	eax,ecx

smp06:	pop	edi
	pop	esi
	pop	edx
	pop	ecx
	pop	ebx
	ret	

smptb	db	255,255,255,254,254,253,253,252
	db	252,251,251,250,249,249,248,248
	db	247,246,246,245,244,244,243,243
	db	242,241,240,240,239,238,238,237
	db	236,236,235,234,233,233,232,231
	db	230,229,229,228,227,226,225,225
	db	224,223,222,221,221,220,219,218
	db	217,216,215,214,214,213,212,211
	db	210,209,208,207,206,205,204,204
	db	203,202,201,200,199,198,197,196
	db	195,194,193,192,191,190,189,188
	db	187,186,185,184,183,182,181,180
	db	179,178,177,176,175,174,172,171
	db	170,169,168,167,166,165,164,163
	db	162,161,160,158,157,156,155,154
	db	153,152,151,150,148,147,146,145
	db	144,143,142,141,139,138,137,136
	db	135,134,133,132,130,129,128,127
	db	126,125,123,122,121,120,119,118
	db	117,115,114,113,112,111,110,108
	db	107,106,105,104,103,101,100,099
	db	098,097,096,094,093,092,091,090
	db	089,087,086,085,084,083,082,080
	db	079,078,077,076,075,073,072,071
	db	070,069,068,067,065,064,063,062
	db	061,060,058,057,056,055,054,053
	db	052,051,049,048,047,046,045,044
	db	043,042,040,039,038,037,036,035
	db	034,033,032,030,029,028,027,026
	db	025,024,023,022,021,020,019,018
	db	016,015,014,013,012,011,010,009
	db	008,007,006,005,004,003,002,001

	db	000,000,001,001,001,002,002,002
	db	003,003,003,003,004,004,004,005
	db	005,005,005,006,006,006,006,007
	db	007,007,007,008,008,008,008,009
	db	009,009,009,009,010,010,010,010
	db	010,011,011,011,011,011,011,012
	db	012,012,012,012,012,013,013,013
	db	013,013,013,013,014,014,014,014
	db	014,014,014,014,014,015,015,015
	db	015,015,015,015,015,015,015,015
	db	015,016,016,016,016,016,016,016
	db	016,016,016,016,016,016,016,016
	db	016,016,016,016,016,016,016,016
	db	016,016,016,016,016,016,016,016
	db	016,016,016,016,016,016,016,016
	db	016,016,016,016,016,016,016,016
	db	016,016,016,016,016,016,016,016
	db	016,016,015,015,015,015,015,015
	db	015,015,015,015,015,015,015,015
	db	014,014,014,014,014,014,014,014
	db	014,014,014,013,013,013,013,013
	db	013,013,013,013,012,012,012,012
	db	012,012,012,012,012,011,011,011
	db	011,011,011,011,011,010,010,010
	db	010,010,010,010,009,009,009,009
	db	009,009,009,008,008,008,008,008
	db	008,008,007,007,007,007,007,007
	db	007,006,006,006,006,006,006,005
	db	005,005,005,005,005,004,004,004
	db	004,004,004,003,003,003,003,003
	db	003,002,002,002,002,002,002,001
	db	001,001,001,001,001,000,000,000

sndVoiceChange	endp

cseg	ends
	end
