Propeller Diary (3)

Yoichi Nagashima


Propeller Diary (1)

Propeller Diary (2)

Thursday 20th, March 2008

The audio input circuit to which the sound can be input with the audio output circuit output to not only the video outlet that has already been experimented but also the headphone amplifier of the stereo and the capacitor mike of onboard is installed in Propeller Demo Board. The audio relation decided to be examined as follows because there was no hand that did not experiment on this. In the Introduction article on transistor technology Thereat, the sound of the mike had written it was good there as the speech voice had been reproduced as a sample.

The following queued up in the category of Speech & Sound when looking for the one that it seemed from the library of The Propeller Object Exchange on the download page of the site of Propeller.

  • Singing (16th Century, 4-part Harmony)
  • Singing (Seven)
  • Vocal Tract
  • Stereo Spatializer
"Sing" demonstration is for the time being in the library of use from the first sample like the previous state two. the following two

Having gone out of the headphone terminal of Propeller Demo Board is the following when downloading immediately first, defrosting "Singing (16th Century, 4-part Harmony)" for the time being, specifying SingingDemo.spin with Propeller Tool, and compiling and executing it with F10. (644KB MP3) The noise is quite done though is.

Next, "Singing (Seven)" is downloaded. It defrosts, and SingingDemoSeven.spin is specified with Propeller Tool. Having gone out of the headphone terminal of Propeller Demo Board is the following when compiling and executing it with F10 for the time being. (1.7MB MP3) Here is quite done.

In the system of Propeller, the capacity of internal RAM of each Cogs is not only very small but also RAM that has it on the chip together is considerably small. Moreover, there is no ROM that the user can store except font and signature/data table log. And, external storage is optional EEPROM, in short, if it is neither "Reproduction" it is nor "Real-time synthesis", this long large sound data cannot be achieved. It is terrible there.

It has been understood that this "Speak" function also demonstrates only as no library used from the program sung to examine the third "Vocal Tract" single. Propeller ToolでVocalTractDemo_mama.spinを指定して、 VocalTractDemo_mama.spin is specified with Propeller Tool. Having gone out of the headphone terminal of Propeller Demo Board is the following when compiling and executing it with F10 for the time being. (736KB MP3) This continues endlessly. Because the seen feeling was very simplest, this decided to copy all spin sources of the relation onto the work area as follows, and to examine it.

The upper row is a call side among Propeller Tool screens of the screen shot above. The principle to which it neatly synthesizes the phoneme and the formant has been synthesized is drawn at the beginning of VocalTract in the called the lower.

The part of the audio I/O is the following among the schematic diagrams of Propeller Demo Board. Because the demonstration actually moves with this circuit, the audio output port is P10 and P11. Perhaps, it seems to be going to examine no detecting phase smooth do circuit, and either very to become an analog audio signal by this around here expecting that it might be PWM as much as GAINER.

In addition, the video outlet is used as a monitor using the library of the MIDI input and the MIDI output because it experiments where it is possible to go by basically integrating current object properties.

  • The MIDI input is output in MIDI through in software.
  • The hexadecimal of the video screen is displayed this MIDI information.
  • (ringing)VocalTract is turned on and off from Max/MSP by specific MIDI information.
  • Max/MSP properly controls other voice synthesis parameters.
It remodeled it aiming at the function as follows. Though there is so will being not to enter the voice synthesis in Propeller It was possible to do firmly quite, and it became the experiment tool of interesting "Voice sound".
{{ exp013.spin }}

CON
	_clkmode = xtal1 + pll16x
	_xinfreq = 5_000_000
	jj = 19

OBJ
	Num : "Numbers"
	TV : "TV_Terminal"
	midiIn : "MidiIn03"
	midiOut : "MidiOut01"
	v[4] : "VocalTract"

VAR
	long  stackspace[40]
	byte  aa,ga,gp,vp,vr,f1,f2,f3,f4,na,nf,fa,ff

PUB Main | dummy
	Num.Init
	TV.Start(12)

	TV.Str(string("MIDI_input_Cog ="))
	dummy := midiIn.start(7)
	TV.Str(Num.ToStr(dummy, Num#DEC)) 
	TV.Str(string(", MIDI_output_Cog ="))
	dummy := midiOut.start(6)
	TV.Str(Num.ToStr(dummy, Num#DEC)) 

	TV.Str(string(", Audio_output_Cog ="))
	dummy := v.start(@aa, 10, 11, 4_500_000) - 1
	TV.Str(Num.ToStr(dummy, Num#DEC)) 

	v.set_attenuation(0)
	v.set_pace(100)
	vp := 48
	vr := 1

	repeat
		dummy := midiIn.event
		if dummy <> -1
			midiOut.fifoset(dummy)
			TV.Str(Num.ToStr(dummy, Num#HEX7))
		if dummy == $903064
			Seven
		elseif (dummy & $FFFF00) == $B00000
			v.set_pace( 2 * (dummy & $00007F))
		elseif (dummy & $FFFF00) == $B00100
			vp := dummy & $00007F
		elseif (dummy & $FFFF00) == $B00200
			vr := dummy & $00007F

PRI Seven
	setformants(470,1650,2500,3500)
	gp := 100
	ff := 180                                             
	v.go(10)
	fa := 40
	v.go(150)
	fa := 0
	aa := 25  
	v.go(100)
	ga := 70
	setformants(700,1750,2500,3500)
	v.go(70)
	setformants(700,1500,2400,3400)
	v.go(150)
	setformants(600,1440,2300,3300)
	v.go(50)
	ga := 10
	aa := 0
	ff := 250 
	v.go(20)
	fa := 10
	v.go(20)
	v.go(80)
	fa := 0
	v.go(20)
	ga := 70
	aa := 15
	setformants(500,1440,2300,3300)
	v.go(20)
	setformants(550,1750,2400,3400)
	v.go(60)
	v.go(50)
	setformants(250,1700,2300,3400)
	setnasal(2000)
	na := $FF  
	v.go(60)
	ga := 60
	v.go(150)
	ga := 0
	aa := 0
	v.go(80)
	na := 0
	v.go(500)

PRI set(i)
	f1 := (f1s[i] + jj/2) / jj
	f2 := (f2s[i] + jj/2) / jj
	f3 := (f3s[i] + jj/2) / jj
	f4 := (f4s[i] + jj/2) / jj

PRI setformants(sf1,sf2,sf3,sf4)
	f1 := (sf1 + jj/2) / jj  <# 255
	f2 := (sf2 + jj/2) / jj  <# 255
	f3 := (sf3 + jj/2) / jj  <# 255
	f4 := (sf4 + jj/2) / jj  <# 255

PRI setnasal(f)
	nf := (f + jj/2) / jj <# 255

DAT
'       byte  aa,ga,gp,vp,vr,f1,q1,f2,q2,f3,q3,f4,q4,fn,qn,fa,ff   
note    byte  0,2,4,5,7,9,11,12,11,9,7,5,4,2,0,0

s1      byte  '0,0,0,0,0,670/jj,qx1,1033/jj,qx2,2842/jj,qx3,3933/19,qx4,0,0,0,0,0,0
s2      byte  40,000,100,0,0,0/16,2300/16,3000/16,3500/16,255,2000/16,0,0,0
s3      byte  20,200,100,0,0,250/16,2300/16,3000/16,3500/16,0,0,0,0,0
s4      byte  20,200,100,0,0,250/16,2300/16,3000/16,3500/16,0,0,0,0,0
s5      byte  40,200,100,5,20,700/16,1800/16,2550/16,3500/16,0,0,0,0,0
s6      byte  00,000,100,0,0,425/16,1000/16,2400/16,3500/16,0,0,0,0,0

        '     ee   i    e    a    o    oh   foot boot r    l    uh
f1s     long  0280,0450,0550,0700,0775,0575,0425,0275,0560,0560,0700
f2s     long  2040,2060,1950,1800,1100,0900,1000,0850,1200,0820,1300
f3s     long  3040,2700,2600,2550,2500,2450,2400,2400,1500,2700,2600
f4s     long  3600,3570,3400,3400,3500,3500,3500,3500,3050,3600,3100

q1s     byte  $9A, $9A, $9A, $9A, $9A, $9A, $9A, $9A, $9A, $9A, $98
q2s     byte  $98, $98, $98, $98, $98, $98, $98, $98, $98, $98, $96
q3s     byte  $94, $94, $94, $94, $94, $94, $94, $94, $94, $94, $94
q4s     byte  $92, $92, $92, $92, $92, $92, $92, $92, $92, $92, $90

  • The pronunciation of "7" is started by making a note on the message of "90 30 64".
  • The speed of the pronunciation is controlled by changing "B0 00 **" the control (..drinking.. 2 values).
  • Vibrate pitch is controlled by changing "B0 01 **" the control.
  • Vibrate speed is controlled by changing "B0 02 **" the control.
Though the MIDI transmission and the reception function for confirming the operation are left The pronunciation of "7" has changed here by interest by the slider in the screen on. (most low-speed change) it In the demonstration above, it was vibrate speed as default = 1 vibrate pitch = A long change was done timewise and it was possible to confirm it because it was as 48 and a hurried variation width. Vibrate speed = It becomes a smooth voice by 0, and the compass has changed by vibrate pitch. The screen of the Max/MSP patch made in 1-2 minutes of the side of the control of the parameter of the voice synthesis is the following.

It is the following parts that concretely pronounce, "7". It is one. a variety of so much generation as the time series, and "7" at last When you remarkably reduce the parameter of the pronunciation speed Everything is piled up in FIFO [battea;] even if the following pronunciation start comes in this case by MIDI and it is made to wait though it is also possible to pronounce, "[Se---bu---n-]" in a few seconds. The following pronunciation started if collecting in the buffer when the pronunciation ended.

PRI Seven
	setformants(470,1650,2500,3500)
	gp := 100
	ff := 180                                             
	v.go(10)
	fa := 40
	v.go(150)
	fa := 0
	aa := 25  
	v.go(100)
	ga := 70
	setformants(700,1750,2500,3500)
	v.go(70)
	setformants(700,1500,2400,3400)
	v.go(150)
	setformants(600,1440,2300,3300)
	v.go(50)
	ga := 10
	aa := 0
	ff := 250 
	v.go(20)
	fa := 10
	v.go(20)
	v.go(80)
	fa := 0
	v.go(20)
	ga := 70
	aa := 15
	setformants(500,1440,2300,3300)
	v.go(20)
	setformants(550,1750,2400,3400)
	v.go(60)
	v.go(50)
	setformants(250,1700,2300,3400)
	setnasal(2000)
	na := $FF  
	v.go(60)
	ga := 60
	v.go(150)
	ga := 0
	aa := 0
	v.go(80)
	na := 0
	v.go(500)

PRI setformants(sf1,sf2,sf3,sf4)
	f1 := (sf1 + jj/2) / jj  <# 255
	f2 := (sf2 + jj/2) / jj  <# 255
	f3 := (sf3 + jj/2) / jj  <# 255
	f4 := (sf4 + jj/2) / jj  <# 255

PRI setnasal(f)
	nf := (f + jj/2) / jj <# 255

Basically, the noise is thrust in the resonance models such as the vocal tracts and nasal cavities. Digital filter?[Ni], it seems to simulate the pronunciation of the voice of actual man honestly. Only at the time (frame) given to the go method The pronunciation by 13 kinds of parameters at that time is generated as a phoneme fragment, and this is perceived with the voice by the interpolation connection's being done without interrupt. Remodeling and use seem to be as easy as this example in the future if only the side of spin that calls the processing library by the Propeller assembler is said.

Friday 21th, March 2008

The sound (speech) was emitted by Propeller for the time being. However, an essential part and the digital-to-analog conversion output of the audio output are analyzed and it is necessary to analyze in the following the library and here on the called side when attaching how it is. VocalTract.spin The decipherment is considerably difficult in a quite tricky assembler library though it is interested from the voice synthesis to here. The policy of changing little by little separately making the subset of VocalTract.spin even to retreat for a moment, beating it variously because of the side of Main, and experimenting was taken.

First of all, it decided to aim at the decipherment and understanding remodeling it in the in one's own way remodeling part making yesterday's program completed as verification software of the voice synthesis the state as it is, and making experimental Main and making VocalTract.spin further. In an opening explanation of this VocalTract.spin, there was Cog by 80MHz maximum clock and were a necessity and an audio rate with 20KHz. I want to remodel this to 44.1KHz by all means though it is enough if it is a voice. Moreover, because the digital-to-analog conversion is "Delta modulation", an external circuit is said that it is good only with the RC filter.

The part that related first to this was cut because it was unrelated this time though it seemed to need another Cog to put the voice on the subcarrier of the television in FM. Do not put up a peculiar label respectively, and the parameter As for the change a little, operation becomes abnormal and hangs up to say nothing of no display/silent because it suddenly calls the area defined as a structure by the offset specification. It became a repetition of compiling while feeling fiddling little by little and confirming "Still equal" (The pronunciation operation is done). If it is not an environment that the compilation download can be easily executed with F10 of Propeller Tool, and the test trigger can be put out from Max/MSP easily by way of MIDI, it is honest work that cannot be at all done.

It confirmed it with the Propeller manual because first of all, there were some new descriptions in the first following initialization parts.

'If delta-modulation pin(s) enabled, ready output(s) and ready ctrb for duty mode
	if pos_pin > -1
		dira_[pos_pin >> 5 & 1] |= |< pos_pin
		ctrb_ := $18000000 + pos_pin & $3F
		if neg_pin > -1
			dira_[neg_pin >> 5 & 1] |= |< neg_pin
			ctrb_ += $04000000 + (neg_pin & $3F) << 9

In the pin of the analog output, it is assumed that the description of changing CRTB to the duty mode as a delta modulation is examined back, and the following are the definition parts of the I/O pin.

dira_[pos_pin >> 5 & 1] |= |< pos_pin

Many symbols that had not been seen went out though the same processing was able to be achieved even by other coding.

dira_[pos_pin >> 5 & 1] |= |< pos_pin

dira_[pos_pin >> 5 & 1] |= |< pos_pin

This was with the "Bitwise OR" operator. In a word, the pin is specified the output by setting up only the bit that DIRA specified.

dira_[pos_pin >> 5 & 1] |= |< pos_pin

It has embarrassed it with this part. Because the bit shift of the priority of operator is stronger, the pin numbering shifts from 0 by as much as five bits because it is 31 and becomes 0. Apparently, this was the one for becoming of Propeller 64 port correspondence the future. The object of the bit set becomes dira _ 1, that is, dirb _ 0 for port 32-63 by one standing here.

dira_[0] |= |< pos_pin

Actually, operation did not change, and, in addition, did not change about the way above as follows either.

dira_ |= |< pos_pin

Though it worried because of this symbol It was not DIRA to say nothing of this but a variable, and it turned out back that the set value set here in the initialization routine was forwarded to DIRA.

And, it has obviously turned out this library as follows that it is a considerably tricky structure. First of all, if an opening pertinent part of a part of arranged AudioOut01 that becomes an object is pulled out, it becomes the following.

VAR
	long  cog, tract, pace                                                         
	long  index, attenuation, sample                      	'3 longs       ...must              
	long  dira_, dirb_, ctra_, ctrb_, zzzzz, cnt_         '6 longs       ...be                   
	long  frames[frame_buffer_longs]                      	'many longs    ...contiguous                  

PUB start(parameters, pos_pin, neg_pin)
	dira_ |= (|< pos_pin + |< neg_pin)
	ctrb_ := $18000000 + pos_pin & $3F
	ctrb_ += $04000000 + (neg_pin & $3F) << 9
	tract := parameters
	cnt_ := clkfreq / 20_000
	return cog := cognew(@entry, @attenuation)

DAT
entry
                        org
:zero                   mov     reserves,#0             'zero all reserved data
                        add     :zero,d0
                        djnz    clear_cnt,#:zero
    ------
                        mov     t1,par                  'get dira/dirb/ctra/ctrb
                        add     t1,#2*4
                        mov     t2,#4
:regs                   rdlong  dira,t1
                        add     t1,#4
                        add     :regs,d0
                        djnz    t2,#:regs
                        add     t1,#4                   'get cnt ticks
                        rdlong  cnt_ticks,t1                        
                        mov     cnt_value,cnt           'prepare for initial waitcnt
                        add     cnt_value,cnt_ticks

VAR
	long  cog, tract, pace                                                         
	long  index, attenuation, sample                      	'3 longs       ...must              
	long  dira_, dirb_, ctra_, ctrb_, zzzzz, cnt_         '6 longs       ...be                   
	long  frames[frame_buffer_longs]                      	'many longs    ...contiguous                  

First of all, when this was deleted, it did not operate about VAR area though it was a part of the variable for the television voice cut because it was unnecessary above "zzzzz". The row and total were [kurichikaru] in the variable here definition like being in the comment. And, another variable is defined ahead of that two in VAR area as for the long variable that is the mystery. The hint was here. It is as follows when method "start" of calling when this library starts is paid attention.

PUB start(parameters, pos_pin, neg_pin)
	dira_ |= (|< pos_pin + |< neg_pin)
	ctrb_ := $18000000 + pos_pin & $3F
	ctrb_ += $04000000 + (neg_pin & $3F) << 9
	tract := parameters
	cnt_ := clkfreq / 20_000
	return cog := cognew(@entry, @attenuation)

The option when the assembler is called It is, and can pass the second parameter with "COGNEW (AsmAddress, Parameter)". As a result, the address of the variable of VAR area was handed over to the assembler with the initial address in DAT area. It is the following in the initialization routine of the assembler to receive this.

                        mov     t1,par                  'get dira/dirb/ctra/ctrb
                        add     t1,#2*4
                        mov     t2,#4
:regs                   rdlong  dira,t1
                        add     t1,#4
                        add     :regs,d0
                        djnz    t2,#:regs

When you see PAR of the Propeller manual It was , saying that "COGINIT Or, parameter that had been passed when boot-up was done by COGNEW". In a word, the processing said as follows is done first about this loop.

                        mov     t1,par                  'get dira/dirb/ctra/ctrb
                        add     t1,#2*4
                        rdlong  dira,t1

The address of the variable in VAR area is stored in long variable t1. It was specified for here that it was long variable in the back and a target variable in doing by 2(long) *4(byte) ,in a word, only two. In reading this to DIRA, Direction of the output port is set.

However, a tricky programming still continues. This is supposed to be quite terrible though the following loops turn by four degrees.

		mov     t1,par                  'get dira/dirb/ctra/ctrb
		add     t1,#2*4
		mov     t2,#4
:regs	rdlong  dira,t1
	 add     t1,#4
	 add     :regs,d0
		djnz    t2,#:regs

It reads and four of the movement of former address (t1) is added to the address at each loop because it is 1long and 4bytes size. It is unquestionable for here. The problem is a movement of a reading previous address. In a statement here, such a meaning is not. It is a statement that it is here because it is a label. Moreover, the added offset was described in another place of the source as follows.

' Defined Data
tune	long    $66920000               'scale tuned to 110.00Hz at gp=100 (manually calibrated)
    ------
d0		long    $00000200               'destination/source field increments
d0s0	long    $00000201

Because the numerical value can be defined only up to nine bits about the source area because the instruction is stored in 1long(32bits) in Propeller, it is necessary to define a big constant like "$0200" in the long area like this.

Then, the explanation to which the code is resolved by the binary in the reference of the Alain bra of the Propeller manual is needed. Described in the following

I think the instruction of 1long(32bits) to be 32 bit data. $0200 defined in offset "d0" is added here, and, then, it becomes. 1long(32bits)のインストラクションそのものを32ビットデータと見て、

000010 001i 1111 ddddddddd sssssssss

000000 0000 0000 000000001 000000000

This is a thing that only destination address(ddddddddd) is done the increment, and accesses DIRB in the following address $1F7 while DIRA in address $1F6 was accessed in a in a word opening register of Propeller internal RAM of the figure below a little while ago. In the repetition only of the constant that this enters t2, The data defined in the common area of Propeller can be exactly gotten in Cog.

The program of Propeller, All..external..EEPROM..put..including. It is forwarded to internal RAM of Propeller, and, in addition, the program of each Cog is forwarded to RAM in each Cog. Then, it was included like this example in the instruction, and the feat of doing in the increment and rewriting only the part in the address for the access can be achieved. The common sense of the industry "ROM of building in CPU program" is exactly an opposite. Being possible to recycle by rewriting it is exactly a perceptional change in the area of the program that has already been used if it is said the technique for using limited RAM though till then. It is wonderful.

Saturday 22th, March 2008

Quite without reaching the part of the D/A output of audio The one that the voice synthesis program of the sample was remodeled to a version and a parameter changeable version for MIDI was arranged as follows and brought together. It is possible to experiment on the voice synthesis of considerably wide "7" by this set. The object named Numbers and TV_Terminal is called like default in the Propeller library besides these. Moreover, TV_Terminal calls the object named TV and Graphics further internally.

In the place in which it as mentioned above arranged it It arranged simply leaving the function, and it decided to aim at the entire decipherment and understanding.

OBJ
	Num : "Numbers"
	TV : "TV_Terminal"
	midiIn : "MidiIn03"
	midiOut : "MidiOut01"
	v[4] : "AudioOut02"

First of all, in the definition of the block above OBJ, v 2 and v 1 confirmed operation or the thing that did not change to the following arrays.

v[4] : "AudioOut02"

v : "AudioOut02"

And, it finally made it to the way above. It is the maximum, and this is because enough because of one voice (1 Cog) now four sounds (4 Cogs) for the demonstration of polyphonic of four opinions as for the pronunciation simultaneously. Next, the following numerical values were changed.

CON                                            
	frame_buffers = 8                                     		'frame buffers (2保n)
	frame_bytes = 3 {for stepsize} + 13 {for aa..ff}      '16 bytes per frame
	frame_longs = frame_bytes / 4                         	'4 longs per frame
	frame_buffer_bytes = frame_bytes * frame_buffers
	frame_buffer_longs = frame_longs * frame_buffers

Operation has not changed naturally of ..eight.. 32 16. As for 4, 2, and 1, , operation was the same oppositely here. made fun ..the single sound it.. Then, as follows did the CON block as one for the simplification.

CON                                            
	frame_buffers = 1
	frame_bytes = 16
	frame_longs = 4
	frame_buffer_bytes = 16
	frame_buffer_longs = 4

Because the called following of each phoneme of the pronunciation synthesis become 0 again if 3 and AND are taken even if four is added to index at the origin of this condition, index will not be changed from 0.

PUB go(time)
	repeat while frames[index]
	bytemove(@frames[index] + 3, tract, 13)
	frames[index] |= $01000000 / (time * 100 / pace #> 2)
	index := (index + frame_longs) & constant(frame_buffer_longs - 1)

Therefore, it was confirmed that here was rewritten, and operation did not change.

When you make the buffer a minimum size Because the thing accessed in the index disappeared, the initialization of the variable index was omitted, and the index was replaced with 0. As a result, the movement of the method that calls by the pronunciation start becomes the following, makes no progress here in no zero the frame, and is waited for.

PUB go(time)
	repeat while frames[0]
	bytemove(@frames[0] + 3, tract, 13)
	frames[0] |= $01000000 / (time * 100 / pace #> 2)

Actually, it follows while a certain segment is pronouncing when a new pronunciation start is not accepted, it collects in the buffer, and the pronunciation ends. Three subordinate position bytes of this first 1long(4bytes) are the following temporal data, and have one high rank byte (the fourth byte) with "breath volume" of the pronunciation parameter. It is assumed that the processing of the pronunciation before doesn't end and doesn't enter as follows if this doesn't become all 0. Four head bytes of the frame data : in 0 as for "Processing OK". The three head bytes are skipped, and 13 bytes specified by "tract" are frames from the fourth byte over 13 bytes though the area of 4longs(16bytes) is here.

VAR
	long  cog, tract, pace                                                         
	long  index, attenuation, sample                      '3 longs       ...must              
	long  dira_, dirb_, ctra_, ctrb_, zzzzz, cnt_         '6 longs       ...be                   
	long  frames[frame_buffer_longs]                      'many longs    ...contiguous                  

PUB start(parameters, pos_pin, neg_pin)
	dira_ |= (|< pos_pin + |< neg_pin)
	ctrb_ := $18000000 + pos_pin & $3F
	ctrb_ += $04000000 + (neg_pin & $3F) << 9
	tract := parameters
	cnt_ := clkfreq / 20_000
	return cog := cognew(@entry, @attenuation)

It is an address that calls and has been passed from former method of parents as the first parameter above tract. The initial address where 13 byte variables of the voice synthesis parameter were exactly arranged is handed over because this is as follows on the call side.

VAR
	long  stackspace[40]
	byte  aa,ga,gp,vp,vr,f1,f2,f3,f4,na,nf,fa,ff
	byte  jj

PUB Main | dummy
	Num.Init
	TV.Start(12)
	TV.Str(string("Audio_output_Cog ="))
	dummy := v.start(@aa, 10, 11)
	TV.Str(Num.ToStr(dummy, Num#DEC)) 
	v.set_attenuation(0)
	v.set_pace(100)
	vp := 48
	vr := 1
	jj := 19

As a result, the parameter of the method of parents must be referred to from the Propeller assembler of the method of the child. To three head bytes in the third line The temporal data that responds to time that it is pace, and is the pronunciation continuance time that is the pronunciation speed is stored as the first stage value. This data : in an infinite loop of the audio output processing. It seems to be [dei;kurimento]ed hour by hour)(pronunciation completion, and can the following pronunciation if vanishing.

The CON block also disappeared and, in addition, an uncertain part disappeared here at the beginning by this about AudioOut02 in the part as follows refreshingly.

VAR
	long  cog, tract, pace, index, attenuation, sample    '6 longs       ...must              
	long  dira_, dirb_, ctra_, ctrb_, zzzzz, cnt_         '6 longs       ...be                   
	long  frames[4]                                       'many longs    ...contiguous                  

PUB start(parameters, pos_pin, neg_pin)
	dira_ |= (|< pos_pin + |< neg_pin)
	ctrb_ := $18000000 + pos_pin & $3F
	ctrb_ += $04000000 + (neg_pin & $3F) << 9
	tract := parameters
	cnt_ := clkfreq / 20_000
	return cog := cognew(@entry, @attenuation)

PUB set_attenuation(level)
	attenuation := level

PUB set_pace(percentage)
	pace := percentage

PUB go(time)
	repeat while frames[0]
	bytemove(@frames[0] + 3, tract, 13)
	frames[0] |= $01000000 / (time * 100 / pace #> 2)

It searched for the initialization part of the Propeller assembler that existed receiving this, and continuously at the head of DAT block. It is an area the following from label entry that is called from the start method.

DAT

entry
                        org
:zero      		mov     reserves,#0             	'zero all reserved data
                        add     :zero,d0
                        djnz    clear_cnt,#:zero
                        mov     t1,#2*15                'assemble 15 multiply steps into reserves
:minst         	mov     mult_steps,mult_step    '(saves hub memory)
                        add     :minst,d0s0             
                        test    t1,#1           wc
        if_c            sub     :minst,#2
                        djnz    t1,#:minst
                        mov     mult_ret,antilog_ret    'write 'ret' after last instruction
                        mov     t1,#13                  	'assemble 13 cordic steps into reserves
:cstep        	mov     t2,#8                   		'(saves hub memory)
:cinst         	mov     cordic_steps,cordic_step
                        add     :cinst,d0s0
                        djnz    t2,#:cinst
                        sub     :cinst,#8
                        add     cordic_dx,#1
                        add     cordic_dy,#1
                        add     cordic_a,#1
                        djnz    t1,#:cstep                       
                        mov     cordic_ret,antilog_ret  'write 'ret' over last instruction
                        mov     t1,par                  	'get dira/dirb/ctra/ctrb
                        add     t1,#2*4
                        mov     t2,#4
:regs       	rdlong  dira,t1
                        add     t1,#4
                        add     :regs,d0
                        djnz    t2,#:regs
                        add     t1,#4                   'get cnt ticks
                        rdlong  cnt_ticks,t1                        
                        mov     cnt_value,cnt           'prepare for initial waitcnt
                        add     cnt_value,cnt_ticks

It is a part of the following variable partitionings that corresponds to this. It seems to set the parameter basically here, and there to be a part only of Propeller, too.

reserves                                                'reserved registers that get cleared on startup
frqa_center             res     1                       
cnt_ticks               res     1
cnt_value               res     1
frame_index             res     1
frame_ptr               res     1
frame_cnt               res     1
step_size               res     1
step_acc                res     1                                                
vphase                  res     1
gphase                  res     1
fphase                  res     1
f1x                     res     1
f1y                     res     1
f2x                     res     1
f2y                     res     1
f3x                     res     1
f3y                     res     1
f4x                     res     1
f4y                     res     1
nx                      res     1
a                       res     1
x                       res     1
y                       res     1
t1                      res     1
t2                      res     1
par_curr                                                '*** current parameters
aa                      res     1                       'aspiration amplitude
ga                      res     1                       'glottal amplitude       
gp                      res     1                       'glottal pitch
vp                      res     1                       'vibrato pitch           
vr                      res     1                       'vibrato rate            
f1                      res     1                       'formant1 frequency      
f2                      res     1                       'formant2 frequency
f3                      res     1                       'formant3 frequency
f4                      res     1                       'formant4 frequency
na                      res     1                       'nasal amplitude
nf                      res     1                       'nasal frequency
fa                      res     1                       'frication amplitude
ff                      res     1                       'frication frequency
par_next                res     13                      '*** next parameters
par_step                res     13                      '*** parameter steps
mult_steps              res     2 * 15                  'assembly area for multiply steps w/ret
mult_ret
sine_ret                res     1
cordic_steps            res     8 * 13 - 1              'assembly area for cordic steps w/ret
cordic_ret              res     1

First of all, the first following parts : in the area where the constant is defined when sequentially confirming it.

:zero      		mov     reserves,#0             	'zero all reserved data
                        add     :zero,d0
                        djnz    clear_cnt,#:zero

clear_cnt long $1F0 - reserves 'number of reserved registers to clear on startup

I understand everything from the first label in the variable area to an internal register memory with the above-mentioned because it is. The following statements become "Instruction that rewrites oneself" here.

:zero mov reserves,#0 'zero all reserved data

First of all, 0 of the initial values enters the variable named first reserves. D0 is a constant named $200 like there was continuing yesterday. When this is added to label ":zero" with the statement above, it becomes addition as follows.

000010 001i 1111 ddddddddd sssssssss

000000 0000 0000 000000001 000000000

It becomes .."It moves only by one address mov ahead".. kite as an instruction. Because this loops Consequently, "All variables from reserves are initialized by 0" is done. The following parts become important points in this initialization following this.

                        mov     t1,#2*15                'assemble 15 multiply steps into reserves
:minst         	mov     mult_steps,mult_step    '(saves hub memory)
                        add     :minst,d0s0             
                        test    t1,#1           wc
        if_c            sub     :minst,#2
                        djnz    t1,#:minst
                        mov     mult_ret,antilog_ret    'write 'ret' after last instruction

First of all, the constant of 2*15=30 is set in t1. 2*15=30 the following in the vicinity of the end of the block of reserves m in which longs is defined.

mult_steps res 2 * 15 'assembly area for multiply steps w/ret

The forwarding origin is the following and a put label in the program.

---・
' Multiply
'   in:         t1 = unsigned multiplier (15 top bits used)
'               t2 = signed multiplicand (17 top bits used)
'   out:        t1 = 32-bit signed product
mult                    shr     t1,#32-15               'position unsigned multiplier
                        sar     t2,#15                  'position signed multiplicand
                        shl     t2,#15-1
                        jmp     #mult_steps             'do multiply steps
mult_step               sar     t1,#1           wc      'multiply step that gets assembled into reserves (x15)
        if_c            add     t1,t2                   
' Cordic rotation
'   in:          a = 0 to <90 degree angle (~13 top bits used)
'              x,y = signed coordinates     
'   out:       x,y = scaled and rotated signed coordinates
cordic                  sar     x,#1                    'multiply (x,y) by %0.10011001 (0.60725 * 0.984)                   
                        mov     t1,x                    '...for cordic pre-scaling and slight damping         
---・

The statement of 1long at the position of this label is copied onto offset 0 of the forwarding site. Hereafter, the continuing source addition value is defined.

d0s0 long $00000201

This will do "It moves the mov origin and mov ahead only by one address" as an instruction by addition as follows. It is a thing of changing the source and Destination at the same time.

000010 001i 1111 ddddddddd sssssssss

000000 0000 0000 000000001 000000001

However, because the following are here, LSB of decreased t1 is put in carry and it returns it based on secondarily a in a word advanced with great pains in this part "sssssssss" of the source in the code at intervals of one byte address.

                         test    t1,#1           wc
        if_c            sub     :minst,#2

Though here is actually "Multiplication by the bit shift and addition" routine It is a thing of not wanting to arrange "Bit shift and addition" as many as 15 times uselessly as a program and to put it. In a word, only the following two lines have been spent as an element to compose multiplication in an original program (common RAM of Propeller).

mult_step              sar     t1,#1           wc      'multiply step that gets assembled into reserves (x15)
        if_c            add     t1,t2                   

And, the (2*15=30 longs) place is prepared in RAM in Cog. The multiplication operation subroutine was able to be prepared internally as follows as a result by the execution of this initialization.

mult_steps    	sar     t1,#1           wc
        if_c            add     t1,t2                   
 	        	   sar     t1,#1           wc
        if_c            add     t1,t2                   
 	        	   sar     t1,#1           wc
        if_c            add     t1,t2                   
 	        	   sar     t1,#1           wc
        if_c            add     t1,t2                   
 	        	   sar     t1,#1           wc
        if_c            add     t1,t2                   
 	        	   sar     t1,#1           wc
        if_c            add     t1,t2                   
 	        	   sar     t1,#1           wc
        if_c            add     t1,t2                   
 	        	   sar     t1,#1           wc
        if_c            add     t1,t2                   
 	        	   sar     t1,#1           wc
        if_c            add     t1,t2                   
 	        	   sar     t1,#1           wc
        if_c            add     t1,t2                   
 	        	   sar     t1,#1           wc
        if_c            add     t1,t2                   
 	        	   sar     t1,#1           wc
        if_c            add     t1,t2                   
 	        	   sar     t1,#1           wc
        if_c            add     t1,t2                   
 	        	   sar     t1,#1           wc
        if_c            add     t1,t2                   
 	        	   sar     t1,#1           wc
        if_c            add     t1,t2                   

The exit of the anti log operation, and it became common, and return of the return address of this routine newly made according to the following following this.

mov mult_ret,antilog_ret 'write 'ret' after last instruction

As the variable securing, even "res 1" is omitted, and the storage location is shared with the following sine_ret. Uselessness omits to the utmost limit, is raised the maximum efficiency, and feels even the aesthetics of Propeller.

It is initialization of the routine of "Cordic rotation" that continues to this. It was the following when thinking CODEC when examining it with CORDIC.

CORDIC (digit-by-digit method, Volder's algorithm) (for COordinate Rotation DIgital Computer) is a simple and efficient algorithm to calculate hyperbolic and trigonometric functions. It is commonly used when no hardware multiplier is available (e.g., simple microcontrollers and FPGAs) as the only operations it requires are addition, subtraction, bitshift and table lookup.
In short, it is a technique for achieving it by a data table and a simple repetition operation as for a trigonometric operation. This will be able to be used in the future. The delta value of the angle is defined in 13 kinds by the constant as follows for this.. CORDIC.
cordic_delta   	long    $4B901476               'cordic angle deltas (first is h80000000)
                        long    $27ECE16D
                        long    $14444750
                        long    $0A2C350C
                        long    $05175F85
                        long    $028BD879                                       
                        long    $0145F154
                        long    $00A2F94D
                        long    $00517CBB
                        long    $0028BE60
                        long    $00145F30
                        long    $000A2F98

In addition, the variable area is secured as follows.

cordic_steps            res     8 * 13 - 1              'assembly area for cordic steps w/ret
cordic_ret              res     1

And, it turns as follows by a double loop and it forwards it.

                        mov     t1,#13                  	'assemble 13 cordic steps into reserves
:cstep        	mov     t2,#8                   		'(saves hub memory)
:cinst         	mov     cordic_steps,cordic_step
                        add     :cinst,d0s0
                        djnz    t2,#:cinst
                        sub     :cinst,#8
                        add     cordic_dx,#1
                        add     cordic_dy,#1
                        add     cordic_a,#1
                        djnz    t1,#:cstep                       
                        mov     cordic_ret,antilog_ret  'write 'ret' over last instruction

Processing by this forwarding loop developed with internal RAM of Propeller as a subroutine of 13 block that changed the parameter little by little when it was assumed to be one block to process eight lines in the forwarding origin as follows and was secured.

cordic_step             mov     a,a             wc      'cordic step that gets assembled into reserves (x13)
                        mov     t1,y                    
cordic_dx               sar     t1,#1                   '(source incremented for each step)
                        mov     t2,x
cordic_dy               sar     t2,#1                   '(source incremented for each step)
                        sumnc   x,t1
                        sumc    y,t2
cordic_a                sumnc   a,cordic_delta          '(source incremented for each step)

It became "ret" in a common place to the return of the CORDIC processing. It was initialization of the following Propeller registers that had already been examined that continued to this. Because this looks easy now, it is mysterious.

                        mov     t1,par                  	'get dira/dirb/ctra/ctrb
                        add     t1,#2*4
                        mov     t2,#4
:regs       	rdlong  dira,t1
                        add     t1,#4
                        add     :regs,d0
                        djnz    t2,#:regs

And, the following lead to the last part of initialization.

                        add     t1,#4                   'get cnt ticks
                        rdlong  cnt_ticks,t1                        
                        mov     cnt_value,cnt           'prepare for initial waitcnt
                        add     cnt_value,cnt_ticks

Because the clock value corresponding to the audio processing rate had been defined, this was loaded into RAM in Cog. Two lines following this are "Vocal Tract Loop" afterwards. It is a setting of time for back ground (infinite loop) processing every sampling period. Initialization..the..meaning..all..clear. It is so, and it is so if it is said the perfection of the Alain bra if it is said it is too tricky.

Next yes is, and is a part of the processing done every sampling period of 20KHz. 20KHz is 50 microseconds. Because the instructions in Cog are 80MHz the clock of Propeller, and are 4 clocks or 8 clocks They are 1000 instructions or less in 50nsec and this with 20MHz every sampling period when they are four clocks. However, might the showing exactly place of the arm of the programming because it needs it by 22 clocks or less until the turn turns to my Cog when common in Propeller RAM is accessed by the rdlong/wrlong instruction around here.

Actually, the voice under the octave sampling becoming half when 20_000 was made 10_000 and half (10KHz) was. However, it did not come back at all with 30_000(30KHz). Up to even 25KHz and 21KHz managed to be useless when trying then little by little, and it was 20.2KHz to go out. Considerably, it seems to be a library that counts leading, and was the tuning to the very limit. 実際、20_000を10_000と半分(10KHz)にしてみると、

Well, the routine is considerably Chodai. In addition, CALL does the subroutine of the signature, multiplication, the anti log, and CORDIC on the way. Because this has been simplified to a single frame, it seems can do nothing but attack it around here though it seems to process [fure-muindekkusu] for the time being around in the last block.

' Vocal Tract Loop
' Wait for next sample period, then output sample

loop                    waitcnt cnt_value,cnt_ticks     'wait for sample period
                        rdlong  t1,par                  'perform master attenuation
                        sar     x,t1
                        mov     t1,x                    'update duty cycle output for pin driving
                        add     t1,h80000000
                        mov     frqb,t1
                        mov     t1,par                  'update sample receiver in main memory
                        add     t1,#1*4
                        wrlong  x,t1
:White_noise_source     test    lfsr,lfsr_taps  wc      'iterate lfsr three times
                        rcl     lfsr,#1
                        test    lfsr,lfsr_taps  wc
                        rcl     lfsr,#1
                        test    lfsr,lfsr_taps  wc
                        rcl     lfsr,#1
:Aspiration             mov     t1,aa                   'aspiration amplitude
                        mov     t2,lfsr
                        call    #mult                        
                        sar     t1,#8                   'set x
                        mov     x,t1
:Vibrato                mov     t1,vr                   'vibrato rate
                        shr     t1,#10
                        add     vphase,t1
                        mov     t1,vp                   'vibrato pitch
                        mov     t2,vphase
                        call    #sine                        
                        add     t1,gp                   'sum glottal pitch (+) into vibrato pitch (+/-)
:Glottal_pulse          shr     t1,#2                   'divide final pitch by 3 to mesh with
                        mov     t2,t1                   '...12 notes/octave musical scale
                        shr     t2,#2                   '(multiply by %0.0101010101010101)
                        add     t1,t2                                                             
                        mov     t2,t1
                        shr     t2,#4
                        add     t1,t2
                        mov     t2,t1
                        shr     t2,#8
                        add     t1,t2
                        add     t1,tune                 'tune scale so that gp=100 produces 110.00Hz (A2)
                        call    #antilog                'convert pitch (log frequency) to phase delta
                        add     gphase,t2
                        mov     t1,gphase               'convert phase to glottal pulse sample
                        call    #antilog    
                        sub     t2,h40000000
                        mov     t1,ga
                        call    #sine
                        sar     t1,#6                   'add to x
                        add     x,t1
:Vocal_tract_formants   mov     y,#0                    'reset y
                        mov     a,f1                    'formant1, sum and rotate (x,y) 
                        add     x,f1x                   
                        add     y,f1y
                        call    #cordic
                        mov     f1x,x
                        mov     f1y,y
                        mov     a,f2                    'formant2, sum and rotate (x,y) 
                        add     x,f2x                   
                        add     y,f2y
                        call    #cordic
                        mov     f2x,x
                        mov     f2y,y
                        mov     a,f3                    'formant3, sum and rotate (x,y) 
                        add     x,f3x                  
                        add     y,f3y
                        call    #cordic
                        mov     f3x,x
                        mov     f3y,y               
                        mov     a,f4                    'formant4, sum and rotate (x,y)    
                        add     x,f4x                  
                        add     y,f4y
                        call    #cordic
                        mov     f4x,x
                        mov     f4y,y
:Nasal_anti_formant     add     nx,x                    'subtract from x (nx negated)
                        mov     a,nf                    'nasal frequency
                        call    #cordic
                        mov     t1,na                   'nasal amplitude
                        mov     t2,x
                        call    #mult                        
                        mov     x,nx                    'restore x
                        neg     nx,t1                   'negate nx                        
:Frication              mov     t1,lfsr                 'phase noise
                        sar     t1,#3
                        add     fphase,t1
                        sar     t1,#1
                        add     fphase,t1
                        mov     t1,ff                   'frication frequency
                        shr     t1,#1
                        add     fphase,t1
                        mov     t1,fa                   'frication amplitude
                        mov     t2,fphase
                        call    #sine                        
                        add     x,t1                    'add to x
                        jmp     :ret	'run segment of frame handler, return to loop

:ret                    long    :wait                   'pointer to next frame handler routine

:wait                   jmpret  :ret,#loop              '(6 or 17.5 cycles)
                        mov     frame_ptr,par           'check for next frame
                        add     frame_ptr,#8*4          'point past miscellaneous data
                        add     frame_ptr,frame_index   'point to start of frame
                        rdlong  step_size,frame_ptr     'get stepsize
                        and     step_size,h00FFFFFF  wz 'isolate stepsize and check if not 0
        if_nz           jmp     #:next                  'if not 0, next frame ready
                        mov     :final1,:finali         'no frame ready, ready to finalize parameters
                        mov     frame_cnt,#13           'iterate aa..ff
:final                  jmpret  :ret,#loop              '(13.5 or 4 cycles)
:final1                 mov     par_curr,par_next       'current parameter = next parameter
                        add     :final1,d0s0            'update pointers
                        djnz    frame_cnt,#:final       'another parameter?                        
                        jmp     #:wait                  'check for next frame

:next                   add     step_size,#1            'next frame ready, insure accurate accumulation
                        mov     step_acc,step_size      'initialize step accumulator
                        movs    :set1,#par_next         'ready to get parameters and steps for aa..ff
                        movd    :set2,#par_curr   
                        movd    :set3,#par_next
                        movd    :set4,#par_step
                        add     frame_ptr,#3            'point to first parameter
                        mov     frame_cnt,#13           'iterate aa..ff
:set                    jmpret  :ret,#loop              '(19.5 or 46.5 cycles)
                        rdbyte  t1,frame_ptr            'get new parameter
                        shl     t1,#24                  'msb justify
:set1                   mov     t2,par_next             'get next parameter
:set2                   mov     par_curr,t2             'current parameter = next parameter
:set3                   mov     par_next,t1             'next parameter = new parameter
                        sub     t1,t2           wc      'get next-current delta with sign in c            
                        negc    t1,t1                   'make delta absolute (by c, not msb)
                        rcl     vscl,#1         wz, nr  'save sign into nz (vscl unaffected)
                        mov     t2,#8                   'multiply delta by step size
:mult                   shl     t1,#1           wc
        if_c            add     t1,step_size
                        djnz    t2,#:mult
:set4                   negnz    par_step,t1            'set signed step
                        add     :set1,#1                'update pointers for next parameter+step
                        add     :set2,d0
                        add     :set3,d0
                        add     :set4,d0
                        add     frame_ptr,#1
                        djnz    frame_cnt,#:set         'another parameter?
:stepframe              jmpret  :ret,#loop              '(47.5 or 8 cycles)
                        mov     :step1,:stepi           'ready to step parameters
                        mov     frame_cnt,#13           'iterate aa..ff                        
:step                   jmpret  :ret,#loop              '(3 or 4 cycles)
:step1                  add     par_curr,par_step       'step parameter
                        add     :step1,d0s0             'update pointers for next parameter+step
                        djnz    frame_cnt,#:step        'another parameter?                        
                        add     step_acc,step_size      'accumulate frame steps
                        test    step_acc,h01000000  wc  'check for frame steps done
        if_nc           jmp     #:stepframe             'another frame step?        
                        sub     frame_ptr,#frame_bytes  'zero stepsize in frame to signal frame done
                        wrlong  vscl,frame_ptr
                        add     frame_index,#frame_bytes'point to next frame
                        and     frame_index,#frame_buffer_bytes - 1                        
                        jmp     #:wait                  'check for next frame

:finali                 mov     par_curr,par_next       'instruction used to finalize parameters                 
:stepi                  add     par_curr,par_step       'instruction used to step parameters               

It makes no progress as follows in short at the beginning until the sampling period though it is long for a moment.

loop waitcnt cnt_value,cnt_ticks 'wait for sample period

It operates straight here even ahead as follows for the time being according to the voice synthesis parameter in the segment.

------
jmp :ret 'run segment of frame handler, return to loop

It became a voice under the octave that had become half at the sampling period when making it as follows however repeatedly ..useless.. by way of experiment another actually times it as for the first waitcnt.

loop			waitcnt cnt_value,cnt_ticks     'wait for sample period
			waitcnt cnt_value,cnt_ticks
------
Only this can be able to be operated at the same time with the serious one it, and two or more Cogs this, and, because, Propeller will be able ..scaring.. to be called [rubeshi].

Sunday 23th, March 2008

Well, it is yesterday's continuation.

jmp :ret 'run segment of frame handler, return to loop

Following operation processing ahead the above-mentioned The the last part and following three lines have been changed for a moment. As follows, here becomes it in the part where a series of processing ended.

                        jmp     :ret	'run segment of frame handler, return to loop
:ret                    long    :wait                   'pointer to next frame handler routine
:wait                   jmpret  :ret,#loop              '(6 or 17.5 cycles)

The sound not only was emitted when here was changed by the long definition in ":wait" that was the label by the place of previous ":ret" of JMP but also it did not come back from the first pronunciation event to the parents object. It is considerably [kurichikaru].

Here, JMP command of the Propeller manual and JMPRET command were examined. It only jumps to the address in the operand field because it is an unconditional jump [hanoha] literal JMP. It becomes a thing "The value that exists in the RAM(:ret) is considered to be an address and jump there" here because there is no "#" though RAM(:ret) in Cog is specified with the label.

The specification at the jump destination is the ":wait" in ":ret". Then, when you change here The sound not only was emitted but also it did not come back from the first pronunciation event to the parents object. It is quite [kurichikaru].

The code that exists in label ":wait" is the following.

jmpret :ret,#loop

JMPRET It is written in the manual because as follows though it is strange.

JMPRET

Instruction: Jump to address with intention to “return” to another address.

JMPRET RetInstAddr, <#>DestAddress

Result: PC + 1 is written to the s-field of the register indicated by the d-field.

  • RetInstAddr (d-field) is the register in which to store the return address (PC + 1); it should be the address of an appropriate RET or JMP instruction for DestAddress.
  • DestAddress (s-field) is the register or 9-bit literal whose value is the address to jump to.
Explanation

JMPRET stores the address of the next instruction (PC + 1) into the source field of the instruction at RetInstAddr, then jumps to DestAddress. The routine at DestAddress should eventually execute the RET or JMP instruction at the RetInstAddr to return to the stored address (the instruction following the JMPRET).

The Propeller does not use a call stack, so the return address must be stored at the location of the routine’s RET, or returning JMP, command itself. JMPRET is a superset of the CALL instruction; in fact, it is the same opcode as CALL but the i-field and d-field configured by the developer, rather than the assembler.

The return address is written to the RetInstAddr register unless the NR effect is specified.

Considerably mysterious operation is done about CALL apart from JMP because there is no concept of Call stack in Propeller. Cog looks for "Label _ RET" in which RET is put for the previous CALL label when the CALL instruction is executed. And, the address immediately after the CALL instruction is written in the source field of RET (This is a kind of JMP in Propeller), and CALL does JMP previously. It is said that it will return to the following instruction of the place where CALL was put by executing it as JMP to which this is rewritten if there is RET at the end CALL ahead. Actually, instruction bit (opcode) of RET and JMP is corresponding.

It was written that CALL was a subset of JMPRET in the Propeller manual.

Actually, when [imidei;eito] is specified with JMPRET (The address is specified directly by #), instruction bit (opcode) of both is completely corresponding when both are compared as stated above. Then, JMPRET : rather than a kind of JMP. It should be thought that it is a kind of CALL "Jump specified for the following destination".

The address of Inn strike Lang Hsiong of the following line (PC+1) is stored in "RetInstAddr" of the ddddddddd field in JMPRET though the destination was "?????????" in CALL. RetInstAddr of "JMPRET RetInstAddr, <#>DestAddress" that exists in the format is JMP ahead of "The following destination (At the return destination)" it, and <#>DestAddress temporary. Therefore, a temporary destination is first "loop" here of Vocal Tract Loop. And, because the following address of this JMPRET instruction is written in RetInstAddr, it is said that it will return there by RET or JMP having done ahead.

Because RET that also does CALL many times also by the routine of a numeric operation in a series of processing from "loop", and exists there returns to the CALL point in this example, operation is not very refreshing. "..do a series of voice synthesis parameter processing as follows of waitcnt of loop instruction as follows.. ..it is easy to see first of all then..

' Main Loop  - Wait for next sample period, then output sample 

loop		waitcnt cnt_value,cnt_ticks     'wait for sample period
                        call    #sampling_job 
                        jmp     :ret                    'run segment of frame handler, return to loop
:ret			long    :wait                   'pointer to next frame handler routine
:wait		jmpret  :ret,#loop              '(6 or 17.5 cycles)
                        mov     f_ptr,par               'check for next frame
                        add     f_ptr,#8*4              'point past miscellaneous data
                        add     f_ptr,f_index           'point to start of frame
------

' Vocal Tract Job
sampling_job             rdlong  t1,par                  'perform master attenuation
                        sar     x,t1
                        mov     t1,x                    'update duty cycle output for pin driving
                        add     t1,h80000000
------
                        mov     t2,fphase
                        call    #sine                        
                        add     x,t1                    'add to x
sampling_job_ret        ret

As for this, the operation of the voice synthesis was still similarly executed of course. "..here.. ..mystery [nanoha].. ..going out up to now..

Then, the explanation of CALL and JMPRET of the Propeller manual was read in detail and, in addition, solved. The return of CALL destination is next (PC+1) of the CALL instruction. It is RET statement of the place where "Label _ ret" was put that stores it, and the place encodes to the destination area of CALL and is written. It returns by the unconditional jump because (PC+1) is written by Cog there if it is executed and there is previously RET.

# address of [imidei;eito] confirmed no specification to this RetInstAddr about JMPRET because of the error of the compilation experiment though next (PC+1) of the JMPRET instruction was stored in "RetInstAddr" of the ddddddddd field when returning and attaching previously. Then, not # address but the memory (register) is specified. It unconditionally jumps there if there is RET in the destination being referred to the content. There is a possibility that the function that this dynamically rewrites the place that returns while jumping to a destination the same as already seen in the initialization routine can be achieved.

Because DestAddress specifies "#loop" and [imidei;eito] in case of here, instruction bit (opcode) is corresponding to CALL. Return destination (PC+1) is stored at this address of RAM in Cog with ":ret" in RetInstAddr because it is. ":wait" is put on the ":ret" for the time being as long definition. As a result, it flies to the place of ":wait" when "jmp :ret" is executed first.

:NOP etc. that put up the label were put before and behind the line of ":wait", and operation was steady still moreover when having tried and erred before and behind the line of ret" , saying that "Ret: long: the label". And, even if this part was very rewritten to be the following from "long :wait", operation was discovered not to change.

                        jmp     :ret			'run segment of frame handler, return to loop
:ret                    long    :ret                  'pointer to next frame handler routine
:wait                   jmpret  :ret,#loop              '(6 or 17.5 cycles)

However, it was quite useless though not only the "long 0" or long definition in the line of ":ret" but also "NOP" was put or the label of other places was uselessly put. Let's bring it together.

loop                    waitcnt cnt_value,cnt_ticks     'wait for sample period
                        call    #sampling_job
:ng                     nop
                        jmp     :ret                    'run segment of frame handler, return to loop
:ok1                    nop
:ret                    long    :ok2                   'pointer to next frame handler routine
:ok2                    nop
:wait                   jmpret  :ret,#loop              '(6 or 17.5 cycles)

It variously substitutes, it experiments, and the obtained conclusion is the following.

  • OK - ok1 / ret / ok2 / wait
  • ERROR - ng / other labels / other places
Only when this vicinity is shown, it is OK somehow.

At last, the situation was able to be understood here. The block was cut out, the block of the initialization routine was moved to the end in the program part to label, that is, "initial" to confirm it, and the ret instruction was put with the label of "intial_ret" at the end. Moreover, a series of processing that started from loop was cut out by the last "jmp :ret", and moved in the latter half in the program part. However, because the local was exceeded by this movement and it had made an error of ":ret" of a local label, ":ret" of the entire program was changed with "retadd". And, when as follows was done, operation was able to be confirmed even by this.

When the part in the focus is pulled out, here is the following structures.
DAT
entry
			org
			call    #initial
			jmp     #loop
retadd			long    :wait                   'pointer to next frame handler routine  
:wait			jmpret  retadd,#loop              '(6 or 17.5 cycles)

			mov     f_ptr,par               'check for next frame
			add     f_ptr,#8*4              'point past miscellaneous data
------
:final			jmpret  retadd,#loop            '(13.5 or 4 cycles)
------
			jmp     #:wait                  'check for next frame
------
:set			jmpret  retadd,#loop            '(19.5 or 46.5 cycles)
------
:stepframe		jmpret  retadd,#loop            '(47.5 or 8 cycles)
------
:step			jmpret  retadd,#loop            '(3 or 4 cycles)
------
			jmp     #:wait                  'check for next frame
------

' Vocal Tract Job
loop		waitcnt cnt_value,cnt_ticks     'wait for sample period
			rdlong  t1,par                  'perform master attenuation
------
			add     x,t1                    'add to x
			jmp     retadd                  'run segment of frame handler, return to loop

"retadd long :***" is a definition of place where the return address of JMPRET is stored here. In a series of processing after this, the code of "jmpret retadd,#loop" appears many times. It is a usage that this is a meaning of "CALL #loop", and returns to the following place (PC+1) of this code in the system of Propeller. The area of "retadd" is defined here as a storage location in the return place.

Then, as a result of "jmp :ret" of the experiment in the future Contents of address ":ret" are interpreted, and 15 high rank bits are 0 in 32 bit expression as the address (maximum $1FF) in Cog, and this is interpreted in any case of ":ret long :ret" ":ret long :wait" ":ret long :dummy1" as an instruction as NOP. Processing arrives at the line of JMPRET about the continuing address because it is similar.

JMPRET is a super-set of CALL though it is distinctiveness of Propeller. In a sense, JMP is [tta] that is the super-set of RET. Understanding has progressed considerably for the time being though it is necessary to become accustomed around here.

Monday 24th, March 2008

The analysis is still on the way because it considerably had a hard time in CALL and JMPRET. It aimed at a further decipherment and understanding while remodeling and reducing little by little.

Next, it is processing that seems that appearing does the interpolation operation by dividing each frame in the step it. The first part is the following.

                        mov     f_ptr,par               'check for next frame
                        add     f_ptr,#8*4              'point past miscellaneous data
                        rdlong  step_size,f_ptr         'get stepsize
                        and     step_size,h00FFFFFF  wz 'isolate stepsize and check if not 0
        if_nz           jmp     #:next                  'if not 0, next frame ready
                        mov     :final1,:finali         'no frame ready, ready to finalize parameters
                        mov     f_cnt,#13               'iterate aa..ff
:final                  jmpret  retadd,#loop            '(13.5 or 4 cycles)
:final1                 mov     par_curr,par_next       'current parameter = next parameter
                        add     :final1,d0s0            'update pointers
                        djnz    f_cnt,#:final           'another parameter?                        
                        jmp     #:wait                  'check for next frame

In this first part, there is already knowing by sight in initialization.

                        mov     f_ptr,par               'check for next frame
                        add     f_ptr,#8*4              'point past miscellaneous data
                        rdlong  step_size,f_ptr         'get stepsize

First of all, contents of the register are forwarded. @attenuation passed from start method ,in a word, address of VAR variable attenuation because of Boot Parameter in address "$1F0" of internal RAM of Propeller PAR it It is skipped from the following definitions only by just eight variables, and is a variable to add the offset for 8longs here.

VAR
	long  cog, tract, pace, index, attenuation, sample    '6 longs       ...must              
	long  dira_, dirb_, ctra_, ctrb_, zzzzz, cnt_         '6 longs       ...be                   
	long  frames[4]                                       		'many longs    ...contiguous                  

Here is a place in which the temporal data in three bytes and parameters in 13 bytes come. Head long(4bytes) data that exists in sharing RAM in this Propeller is read to the long variable in Cog. This statement is executed between from 7 clocks to 22 clocks. They are 22 clocks if it is immediately after having passed by seven clocks if there is width because it is made to wait by the hardware switching of Cogs and sharing RAM, and [sugu] by chance.

                        and     step_size,h00FFFFFF  wz 'isolate stepsize and check if not 0
        if_nz           jmp     #:next                  'if not 0, next frame ready

In the statement above, Three subordinate position bytes concerning the setting of the time of the segment length are masking done among the data taken into the variable, and it compares it with 0. Of this data's not vanishing, because the processing of a pertinent frame of the pronunciation processing (segment) has not ended yet, it doesn't advance it to the following frame. Processing for no zero continues to "jmp #:next", and the part of processing the following, that is, become 0 on the tip of here this temporal data, and go to the following frame is put in order.

                        mov     :final1,:finali         'no frame ready, ready to finalize parameters
                        mov     f_cnt,#13               'iterate aa..ff
:final                  jmpret  retadd,#loop            '(13.5 or 4 cycles)
:final1                 mov     par_curr,par_next       'current parameter = next parameter
                        add     :final1,d0s0            'update pointers
                        djnz    f_cnt,#:final           'another parameter?                        
                        jmp     #:wait                  'check for next frame

:finali                 mov     par_curr,par_next       'instruction used to finalize parameters                 

The first line is mysterious on the face of things. The code that exists in the label of the forwarding site It is quite the same as the code that exists in the label of the forwarding origin. Though it is complete and seems to be useless if it is usual CPU Because contents of the place of the label actually changed with the loop, it was necessary to initialize it to jump into it first.

The sampling period is consciously called in every case first though it is a loop counter and it is here repeat of 13 times. The increment value is $201. That is, because it is nine bit data and "000000001 000000001", the part of the source and the destination in the code that exists in the label is rewritten for one each + to be done by this loop. And, the following parameter list is copied onto a present parameter list after 13 times.

By the way, because variable frame_index(f_index) is adjusted to minimum one in the experiment here, there are actually neither next nor [kuso], and it operates only by the frame and 1 always written. Then, this part was skipped.

                        and     step_size,h00FFFFFF  wz 'isolate stepsize and check if not 0
        if_nz           jmp     #:next                  'if not 0, next frame ready
                        jmp     #:wait
                        mov     :final1,:finali         'no frame ready, ready to finalize parameters
                        mov     f_cnt,#13               'iterate aa..ff
:final                  jmpret  retadd,#loop            '(13.5 or 4 cycles)
:final1                 mov     par_curr,par_next       'current parameter = next parameter
                        add     :final1,d0s0            'update pointers
                        djnz    f_cnt,#:final           'another parameter?                        
                        jmp     #:wait                  'check for next frame

:finali                 mov     par_curr,par_next       'instruction used to finalize parameters                 

That is, it doesn't care as follows.

                        and     step_size,h00FFFFFF  wz 'isolate stepsize and check if not 0
        if_nz           jmp     #:next                  'if not 0, next frame ready
                        jmp     #:wait                  'check for next frame

Again refreshingly by this. Then, "as follows ..this..:

                        and     step_size,h00FFFFFF  wz 'isolate stepsize and check if not 0
        if_nz           jmp     #:next                  'if not 0, next frame ready
                        jmp     #:wait                  'check for next frame
:next                   add     step_size,#1            'next frame ready, insure accurate accumulation
                        mov     step_acc,step_size      'initialize step accumulator
------
Because another while programming it had not had when referring, it became simpler the following this.
                        and     step_size,h00FFFFFF  wz 'isolate stepsize and check if not 0
        if_z           jmp     #:wait                 'if not 0, next frame ready
                        add     step_size,#1            'next frame ready, insure accurate accumulation
                        mov     step_acc,step_size      'initialize step accumulator
------

The variable has been limited to minimum one for a moment in the following part following this.

         if_nc           jmp     #:stepframe             'another frame step?        
                        sub     f_ptr,#frame_bytes  	'zero stepsize in frame to signal frame done
                        wrlong  vscl,frame_ptr
                        add     f_index,#frame_bytes	'point to next frame
                        and     f_index,#frame_buffer_bytes - 1                        
                        jmp     #:wait                  'check for next frame

Details here will be examined later.

        if_nc           jmp     #:stepframe             'another frame step?        
                        sub     f_ptr,#16               'zero stepsize in frame to signal frame done
                        wrlong  vscl,f_ptr
                        jmp     #:wait                  'check for next frame
The interpolation processing in the step in the frame seems to be done in the following parts when bringing it together. It sometimes goes to the sampling processing. The number of steps from the last access is freshly calculated. It is likely to fail as a sound if this exceeds it. It is the last barrier though is long for a moment.
                        add     step_size,#1            'next frame ready, insure accurate accumulation
                        mov     step_acc,step_size      'initialize step accumulator
                        movs    :set1,#par_next         'ready to get parameters and steps for aa..ff
                        movd    :set2,#par_curr   
                        movd    :set3,#par_next
                        movd    :set4,#par_step
                        add     f_ptr,#3            'point to first parameter
                        mov     f_cnt,#13           'iterate aa..ff
:set                    jmpret  :ret,#loop              '(19.5 or 46.5 cycles)
                        rdbyte  t1,f_ptr            'get new parameter
                        shl     t1,#24                  'msb justify
:set1                   mov     t2,par_next             'get next parameter
:set2                   mov     par_curr,t2             'current parameter = next parameter
:set3                   mov     par_next,t1             'next parameter = new parameter
                        sub     t1,t2           wc      'get next-current delta with sign in c            
                        negc    t1,t1                   'make delta absolute (by c, not msb)
                        rcl     vscl,#1         wz, nr  'save sign into nz (vscl unaffected)
                        mov     t2,#8                   'multiply delta by step size
:mult                   shl     t1,#1           wc
        if_c            add     t1,step_size
                        djnz    t2,#:mult
:set4                   negnz    par_step,t1            'set signed step
                        add     :set1,#1                'update pointers for next parameter+step
                        add     :set2,d0
                        add     :set3,d0
                        add     :set4,d0
                        add     f_ptr,#1
                        djnz    f_cnt,#:set         'another parameter?
:stepframe              jmpret  :ret,#loop              '(47.5 or 8 cycles)
                        mov     :step1,:stepi           'ready to step parameters
                        mov     f_cnt,#13           'iterate aa..ff                        
:step                   jmpret  :ret,#loop              '(3 or 4 cycles)
:step1                  add     par_curr,par_step       'step parameter
                        add     :step1,d0s0             'update pointers for next parameter+step
                        djnz    f_cnt,#:step        'another parameter?                        
                        add     step_acc,step_size      'accumulate frame steps
                        test    step_acc,h01000000  wc  'check for frame steps done
        if_nc           jmp     #:stepframe             'another frame step?        
                        sub     f_ptr,#16               'zero stepsize in frame to signal frame done
                        wrlong  vscl,f_ptr
                        jmp     #:wait                  'check for next frame

:stepi                  add     par_curr,par_step       'instruction used to step parameters               

Tuesday 25th, March 2008

Well, it is yesterday's continuation. There is no problem in the following parts about the beginning. Apparently, the increment seems to be done as for the variable. Moreover, because $00FFFFFF and AND are taken when it rounds It is unquestionable because it becomes 0 in the following ..AND.. judgment even if overflowing ..this... This value is continuously substituted.
                        add     step_size,#1            'next frame ready, insure accurate accumulation
                        mov     step_acc,step_size      'initialize step accumulator
And, a new statement has appeared again in the following continuing parts. It is only Propeller instruction.
                        movs    :set1,#par_next         'ready to get parameters and steps for aa..ff
                        movd    :set2,#par_curr   
                        movd    :set3,#par_next
                        movd    :set4,#par_step
                        add     f_ptr,#3            'point to first parameter
                        mov     f_cnt,#13           'iterate aa..ff
:set                    jmpret  :ret,#loop              '(19.5 or 46.5 cycles)
                        rdbyte  t1,f_ptr            'get new parameter
                        shl     t1,#24                  'msb justify
:set1                   mov     t2,par_next             'get next parameter
:set2                   mov     par_curr,t2             'current parameter = next parameter
:set3                   mov     par_next,t1             'next parameter = new parameter
                        sub     t1,t2           wc      'get next-current delta with sign in c            
                        negc    t1,t1                   'make delta absolute (by c, not msb)
                        rcl     vscl,#1         wz, nr  'save sign into nz (vscl unaffected)
                        mov     t2,#8                   'multiply delta by step size
:mult                   shl     t1,#1           wc
        if_c            add     t1,step_size
                        djnz    t2,#:mult
:set4                   negnz    par_step,t1            'set signed step
                        add     :set1,#1                'update pointers for next parameter+step
                        add     :set2,d0
                        add     :set3,d0
                        add     :set4,d0
                        add     f_ptr,#1
                        djnz    f_cnt,#:set         'another parameter?

"Only part in the source area" What is MOVS among the statements of the object though have not surprised any longer if coming here It is forwarded MOV. What is MOVSD among the statements of the object? "Only part in the destination area" It is forwarded MOV. Though it has not obeyed such transformed MOV an instruction in other CPU "Only part in the instruction area" To Propeller further among the statements of the object MOVI It forwards, and there is MOV, too.

A part of the instruction is rewritten though RAM in limited Cog can be effectively used, and, because, I think it is considerably revolutionary. It is possible to execute it by rewriting the instruction with MOVS and MOVD when becoming MOVI though it seems to be able to use for the batch transmission because of the set. It is an indescribably terrible class of commands.

                        movs    :set1,#par_next         'ready to get parameters and steps for aa..ff
                        movd    :set2,#par_curr   
                        movd    :set3,#par_next
                        movd    :set4,#par_step

The first upper part has only initialized contents of the statement in the back again as well as an example a little while ago.

                         add     f_ptr,#3            'point to first parameter
                        mov     f_cnt,#13           'iterate aa..ff
 

The upper part following this sets in the first pointer of parameters in 16 bytes of 13 areas, and, in addition, sets the frequency of the loop to 13 times (total of the parameter). And, the following are the loop bodies in this part.

:set                    jmpret  :ret,#loop              '(19.5 or 46.5 cycles)
                        rdbyte  t1,f_ptr            'get new parameter
                        shl     t1,#24                  'msb justify
:set1                   mov     t2,par_next             'get next parameter
:set2                   mov     par_curr,t2             'current parameter = next parameter
:set3                   mov     par_next,t1             'next parameter = new parameter
                        sub     t1,t2           wc      'get next-current delta with sign in c            
                        negc    t1,t1                   'make delta absolute (by c, not msb)
                        rcl     vscl,#1         wz, nr  'save sign into nz (vscl unaffected)
                        mov     t2,#8                   'multiply delta by step size
:mult                   shl     t1,#1           wc
        if_c            add     t1,step_size
                        djnz    t2,#:mult
:set4                   negnz    par_step,t1            'set signed step
                        add     :set1,#1                'update pointers for next parameter+step
                        add     :set2,d0
                        add     :set3,d0
                        add     :set4,d0
                        add     f_ptr,#1
                        djnz    f_cnt,#:set         'another parameter?

First of all, the processing at the sampling period is called in the part of following ":set" once and it returns.

:set                    jmpret  :ret,#loop              '(19.5 or 46.5 cycles)
                        rdbyte  t1,f_ptr            'get new parameter
                        shl     t1,#24                  'msb justify

Next, because the parameter in VAR area is byte data, only one byte is read to variable t1 in Cog by the command. And, this shifts left by 24 bits. Because the internal arithmetics are 32 bits, are three subordinate position bytes brought to MSB as a round-down error margin? Three subordinate position bytes of t1 are all 0 for the time being.

:set1                   mov     t2,par_next             'get next parameter
:set2                   mov     par_curr,t2             'current parameter = next parameter
:set3                   mov     par_next,t1             'next parameter = new parameter

The parameter of the following segment is substituted, and a present segment in addition. The parameter of t1 that has been read from sharing RAM (value that shifts by 24 bits) is put in the parameter of the following segment. Each numerical value is put on one most significant byte, and three subordinate position bytes become all 0. And, there was a novel code in this following part again.

                        sub     t1,t2           wc      		'get next-current delta with sign in c            
                        negc    t1,t1                   		'make delta absolute (by c, not msb)
                        rcl     vscl,#1         wz, nr  	'save sign into nz (vscl unaffected)

It is "The current value is pulled from the next value and t1. " in each 13 kinds of parameters. The value is done to the subtraction here as Unsigned. Because each numerical value is put on one most significant byte, three subordinate position bytes of the result are all 0. T1 becomes a delta value (difference value), and the signature bit stands when becoming minus. The following NEGC existed as follows.

It is said that Additive Inverse of SValue is written in RValue if SValue is carry flag =1 if it is carry flag =0. Additive Inverse is "Number that adds and vanishes. " If the operation result immediately before is in short negative because [kokodeha] and both are t1, the minus is put and, in a word, it becomes a meaning of "Absolute value" operation. However, this is a petit-mystery though it is likely not to care separately because there is a command ABS in taking the absolute value, too. And, VSCL appeared suddenly hereafter as follows.

                        sub     t1,t2           wc      		'get next-current delta with sign in c            
                        negc    t1,t1                   		'make delta absolute (by c, not msb)
                        rcl     vscl,#1         wz, nr  		'save sign into nz (vscl unaffected)

This is a special register in Cog of "Vodeo Scale Register" ($1FF) it is originally said that it can use it as a general register though it is the one used for the video generation. However, this Cog doesn't generate the video, and the symbol such as VSCL doesn't appear here as a general purpose. In a word, the register without initialization is said that the left will shift by one bit. It is said that 0 flags are hoisted by optional WZ when the shift result is 0 and the shift result is not written in VSCL very much by optional NR. This is [middo] mystery.

---At last, it saw it by thinking for a while. A petit-mystery and the middle mystery were sets. If it calculates with Unsigned first of all, and the result is negative, the carry flag is put up. And, MSB of source (t1) is brought to the carry flag at the same time though MSB of t1 (signature bit) is adjusted to 0 according to the carry. Apparently, the comment seeming is this meaning.

And, VSCL that doesn't change contents so that the left may shift by one bit The result of "() Carry is put in LSB of VSCL and the left shifts by one bit" is written in 0 flags. 0 flags become one by this execution when carry stands in the former steps, stand this, and 0 flags will stand because it is 0 if clear is done, and carry doesn't stand. Because there is a difference value in the execution result of the former steps, cannot optional WZ of SUB able to be used, and is it done that it is roundabout because of "0 flags of reversing the carry flag" like this? Apparently, the comment : in this thing. "0 flags of reversing the carry flag" It can be interpreted, "No zero flag of the carry flag =". Carry stands if it is not a zero and the minus, ,in a word,, thing.

Keeping is done until the command next, with optional WZ with this result written in 0 flags appears. It is different from CPU usual as for this. And, the following continuing routines are simple "Multiplication" in which optional WR doesn't appear. Incidently, multiplication/division was not ordered in Propeller. First of all, constant # 8 is set in loop counter t2 by the first instruction.

                        mov     t2,#8                   'multiply delta by step size
:mult                   shl     t1,#1           wc
        if_c            add     t1,step_size
                        djnz    t2,#:mult
:set4                   negnz    par_step,t1            'set signed step

If the operation only of here is chased for the time being, it becomes it as follows because three subordinate position bytes of difference value t1 are 0.

  • Difference value t1 shifts left by one bit.
  • MSB that puts out Hami from t1 enters the carry flag.
  • If carry stands, step_size (opening of today appearance) is added to t1.
  • It loops by eight bits this.
To three subordinate position byte part of t1 that 0 In the addition of step_size that is three byte data only when MSB of t1 is one, "High rank one byte * of difference absolute value t1 step_size of three byte data" is splendidly obtained as 32 bit data at the end. The loop originated in this data of eight effect bits eight times.

As a result, if 0 flags are 0 as it is if 0 flags stand by NEGNZ, Additive Inverse of t1 is written as for t1. After all, because optional WZ did not appear on the way of multiplication, Additive Inverse of "Difference absolute value * step_size" will be written effective in here of signature information that keeps and has been done before.

The following following this can already be easily read. Only the source side of the statement is done the increment, and corresponds to the following parameter. And, because additional value d0 is "000000001 000000000" Only the destination is done the increment, and corresponds to the following parameter respectively. Both are the techniques only of the particular field in the code of rewriting it. It similarly turns to all of 13 parameters and it ends.

                        add     :set1,#1                'update pointers for next parameter+step
                        add     :set2,d0
                        add     :set3,d0
                        add     :set4,d0
                        add     f_ptr,#1
                        djnz    f_cnt,#:set         'another parameter?

It is the following parts that remained at the end.

:stepframe              jmpret  :ret,#loop              '(47.5 or 8 cycles)
                        mov     :step1,:stepi           'ready to step parameters
                        mov     f_cnt,#13           'iterate aa..ff                        
:step                   jmpret  :ret,#loop              '(3 or 4 cycles)
:step1                  add     par_curr,par_step       'step parameter
                        add     :step1,d0s0             'update pointers for next parameter+step
                        djnz    f_cnt,#:step        'another parameter?                        
                        add     step_acc,step_size      'accumulate frame steps
                        test    step_acc,h01000000  wc  'check for frame steps done
        if_nc           jmp     #:stepframe             'another frame step?        
                        sub     f_ptr,#16  'zero stepsize in frame to signal frame done
                        wrlong  vscl,f_ptr
                        jmp     #:wait                  'check for next frame

:stepi                  add     par_curr,par_step       'instruction used to step parameters               

As for this, the majority has already settled by the same as above. It copies (re-setting), and it ..13 time of the number of parameters.. loops again by initializing the line. Because the additional value is "000000001 000000001" Both the source and [sutei;ne-shon] are done the increment, and correspond to the following parameter respectively. Contents of the loop are the following.

:step1                  add     par_curr,par_step       'step parameter

In a word, it was calculated soon by contents on. "Difference absolute value * step_size" with the sign is added. This corresponds though the parameter increases or it decreases.

The value in which the increment is done is added to the total value, and it is examined as follows whether the total result exceeded 24 bits following this.

                        add     step_acc,step_size      'accumulate frame steps
                        test    step_acc,h01000000  wc  'check for frame steps done
        if_nc           jmp     #:stepframe             'another frame step?        

The processing of this frame ended, and it continues as follows if it exceeds it.

                        sub     f_ptr,#16  'zero stepsize in frame to signal frame done
                        wrlong  vscl,frame_ptr
                        jmp     #:wait                  'check for next frame

Because [fure-muindekkusu] was assumed to be one here, here is almost meaningless. The pointer returns to the head of the parameter area. And, it is a thing of having cleared frame 0 of the parameter area by using VSCL that has not been changed from 0 of the initial values by chance because the processing of the frame ended here 0. All INFRASTRUCTUREs of the program were examined by this.

It is said as follows that here will be arranged in this program.

  • When the pronunciation start comes, time is set to three head bytes of the parameter.
  • 13 voice synthesis parameters from the parents object are stored.
  • Actual pronunciation processing uses the data of the variable area of 13 parameters.
  • The parameter is interpolating operated at intervals of sampling.
  • The parameter interpolation is done between present of the value and the targeted value.
  • There is a delta value with the sign of each parameter interpolation.
After all, no hint in an essential part of emitting the sound from the output pin of Propeller comes into view here though everything has not been seen yet. However, it came skilled enough about the uniqueness of the assembler of Propeller.

Here, it was noticed that there was a big mistake looking at the renewal. The nature was taken in the call parameter delivery with the bit operator by chance by chance in the place of the start method of initialization, and it flew without touching about the following two lines at all.

PUB start(parameters, pos_pin, neg_pin)
	dira_ |= (|< pos_pin + |< neg_pin)
	ctrb_ := $18000000 + pos_pin & $3F
	ctrb_ += $04000000 + (neg_pin & $3F) << 9
	tract := parameters
	cnt_ := clkfreq / 20_000
	return cog := cognew(@entry, @attenuation)

Only this was actually a hint to output the sound with Propeller. And, it moved as a block by "A series of processing of the voice synthesis parameter" to make the whole easy to see in the latter half of the program and this and the instruction that became a pair were discovered exactly in the part where the subroutine had been called. Even this core more and more will be a direct hit from tomorrow.

Propeller Diary (4)