Home » Archimedes archive » Archimedes World » AW-1996-07.adf » !AcornAns/AcornAns
!AcornAns/AcornAns
This website contains an archive of files for the Acorn Electron, BBC Micro, Acorn Archimedes, Commodore 16 and Commodore 64 computers, which Dominic Ford has rescued from his private collection of floppy disks and cassettes.
Some of these files were originally commercial releases in the 1980s and 1990s, but they are now widely available online. I assume that copyright over them is no longer being asserted. If you own the copyright and would like files to be removed, please contact me.
Tape/disk: | Home » Archimedes archive » Archimedes World » AW-1996-07.adf |
Filename: | !AcornAns/AcornAns |
Read OK: | ✔ |
File size: | 22E55 bytes |
Load address: | FFF3FB46 |
Exec address: | CB17B3C3 |
File contents
�Sound *. � sj *. F�� �� �c 4$ � tj 4$ F��D�� �main $ � V�� $ F������ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <math.h> #define TRACE 0 #include "trace.h" #include "wimpt.h" #include "werr.h" #include "bbc.h" #include "os.h" #include "akbd.h" #include "swis.h" extern int quickdiv_init(int divisor); extern int quickdiv(int numerator); extern int rbbcinc(int r, int k); extern int div_frac16(int number, int divisor); extern int mul_frac16(int x, int a); extern int mul_frac16c(int x, int a); extern int sqrt_frac16(unsigned int x); extern int gauss16(void); extern void sgauss16(int seed); extern int cos16(int a); extern int sin16(int a); extern int exp16(int a); extern int ln16(int a); extern int pow16(int a, int b); extern int acs16(int a); extern int asn16(int a); extern int pitch16(int a); extern char *voice_base; extern char *wave_base; extern char *wave_end; typedef enum {multi, nonmulti} monitor; monitor monitortype; #define diff(a,b) ((a)<(b) ? (b)-(a) : (a)-(b)) #define lone 16 #define one (1<<lone) #define lwts 10 #define wtsize (1<<lwts) #define sres 1024 /*pitch resolution (corresponds to vertical screen res of picture)*/ #define ltran 256 /*loop limit for transient behaviour*/ #define lasym 64 /*loop limit for asymptotic behaviour*/ int wavetable[wtsize]; int pitch[sres]; char *linlog; int sampleperiod; int oldvoice[8]; int voice; /***********************************************************************************************************/ monitor read_monitor_type(void) { int r2; os_swi3r(6, 161,133,0, 0,0,&r2); if ((r2/4 & 3) == 1) return multi; else return nonmulti; } void restore(void) { int v; char *err; wimpt_complain(os_swi2r(Sound_RemoveVoice, 0, voice, (int *)&err, &v)); if (v==0) { printf("error in restore\n"); werr(0, err); } for (v=1; v<=8; v++) wimpt_complain(os_swi2(Sound_AttachVoice, v, oldvoice[v-1])); wimpt_complain(os_swi6(Sound_Configure, 1, 0, 0, 0, 0, 0)); /*wimpt_complain(os_cli("Voices"));*/ } /*takes a phase increment p and finds the note of closest phase increment from array l (of n elements, which stores phase accumulators for notes in last packet) returning the index of that note; this is needed to ensure new notes begin their phase from the end phase of the nearest similar note in the last packet of sound*/ int nearnote(int p, unsigned int *l, unsigned int n) { int i=0; int j=i+n-1; int m; int p1, p2; if (n==0) return 0; /*this shouldn't ever happen!*/ if (n==1) return i; for (;;) { if (n==2) { p1=(l[i]<<16)>>16; p2=(l[j]<<16)>>16; return diff(p1,p)<diff(p2,p) ? i : j; } m = i+n/2; p1 = (l[m]<<16)>>16; if (p1==p) return m; if (p1<p) i=m; else j=m; n=j+1-i; } } BOOL init_globals(void) { int s, i; int *channel_handler; monitortype = read_monitor_type(); for (s=0; s<wtsize; s++) wavetable[s] = sin16(s << lone+2-lwts); /*when converting graph to sound, let vertical component correspond to pitch and vary from 0x2000 (2 octaves below middle C) to 0x8000 (4 octaves above middle C) - change 0x2000 or 0x6000 below to alter this relation*/ for (s=0, i=0x2000; s<sres; s++, i+=0x6000/sres) pitch[s] = pitch16(i); wimpt_complain(os_swi6r(Sound_Configure, 0, 0, 0, 0, 0, 0, 0, 0, &sampleperiod, (int *)&channel_handler, 0, 0)); linlog = (char *)channel_handler[2]; return TRUE; } BOOL input_params(int *dur, int *size, int *dres, int *lmin, int *lmax) { double dbl; BOOL ok; printf("\n\n"); printf(" T h e S o u n d o f C h a o s\n\n\n"); printf("After image/sample generation is complete the sample will play repeatedly.\n\n"); printf("At that point, use:\n\n"); printf(" Escape to end this program,\n"); printf(" Return to re-run it,\n"); printf(" Left/Right cursor (+shift) to seek out interesting new lambda regions\n"); printf(" (followed by any other key to resume playing of current sample).\n\n\n"); do { do { printf("Please enter sample duration in centiseconds (eg 3000 for a 30s sample; must be at least 100) "); scanf("%i", dur); } while (*dur<100); *size = (*dur*10000)/sampleperiod; if (wave_base=malloc(*size), wave_base==0) { printf("Can't allocate sample memory of %i bytes - try a shorter duration or quit & increase free memory, then run again!\n", *size); ok=FALSE; } else ok=TRUE; } while (!ok); wave_end = wave_base+*size; do { printf("Please enter sample resolution (100-10000, suggest 1000) "); scanf("%i", dres); } while (*dres<100 || *dres>10000); do { printf("Please enter lambda min (0-4) "); scanf("%Lf", &dbl); } while (dbl<0 || dbl>4); *lmin = (int)(dbl*one); do { printf("Please enter lambda max (0-4) "); scanf("%Lf", &dbl); } while (dbl<=*lmin/65536.0 || dbl>4); *lmax = (int)(dbl*one); return TRUE; } void add_voice(void) { int v; wimpt_complain(os_swi2r(Sound_InstallVoice, (int)voice_base, 0, 0, &voice)); for (v=1; v<=8; v++) wimpt_complain(os_swi2r(Sound_AttachVoice, v, voice, 0, oldvoice+v-1)); atexit(restore); wimpt_complain(os_swi6(Sound_Configure, 1, 0, 0, 0, 0, 0)); /*wimpt_complain(os_cli("Voices"));*/ } int main(void) { int size; int uservolume, s; int sample; int i; int dur = 6000; /*total sample length in centiseconds*/ int dres = 1000; /*sample duration resolution - make sample up of dres packets of sound (corresponds to horizontal screen res of picture)*/ char selection[sres]; unsigned int list1[sres], list2[sres], *list, *listold; int nnotes, nnotesold; int lmin, lmax, l, x; int li, le, ldif, lr; int q; char *p, *pt; int pi, pe, pr; int sx, si, se, sr; int start_time; if (!init_globals()) return 0; for (;;) { bbc_mode(monitortype==multi ? 20 : 12); if (!input_params(&dur, &size, &dres, &lmin, &lmax)) return 0; ldif = lmax-lmin; list=list1; list2[0]=(0<<16)+pitch[0]; nnotesold=1; listold=list2; bbc_cls(); wimpt_complain(os_swi1r(Sound_Volume, 127, &uservolume)); for (p=pt=wave_base,pi=size/dres,pr=size%dres,pe=-dres, q=0, l=lmin,li=ldif/dres,lr=ldif%dres,le=-dres, sx=0,si=1280/dres,sr=1280%dres,se=-dres; q<dres; q++, l+=li,le+=2*lr,le>0?(l++,le-=2*dres):0, sx+=si,se+=2*sr,se>0?(sx++,se-=2*dres):0) { memset(selection, 0, sres); x = one/2; for (s=0; s<ltran; s++) x = mul_frac16c(l, mul_frac16c(x, one-x)); for (s=0; s<lasym; s++) { x = mul_frac16c(l, mul_frac16c(x, one-x)); i = x*sres/one; if (i<0) i=0; if (i>=sres) i=sres-1; selection[i]=255; bbc_plot(69,sx,i); } nnotes=0; /*now we compile our list of pitches for the current value of lambda*/ for (s=0; s<sres; s++) if (selection[s]) list[nnotes++]=(0<<16)+pitch[s]; /*it then remains to set the initial phase of each such note from the end phase of the nearest note in the last packet*/ for (s=0; s<nnotes; s++) list[s] += (listold[nearnote(list[s], listold, nnotesold)]>>16)<<16; if (quickdiv_init(nnotes)<0) werr(1, "unexpected quickdiv_init error"); for (pt+=pi,pe+=2*pr,pe>0?(pt++,pe-=2*dres):0,pt=(pt>wave_end||q==dres-1)?wave_end:pt; p<pt; p++) { for (i=0, sample=0; i<nnotes; i++) sample += wavetable[(list[i]+=list[i]<<16) >> 32-lwts]; sample = quickdiv(sample); sample >>= 4; if (sample>=4096) sample=4095; if (sample<=-4096) sample=-4095; *p = linlog[(unsigned int)(sample<<19)>>19]; } nnotesold=nnotes; listold=list; list = list==list1 ? list2 : list1; } wimpt_complain(os_swi1(Sound_Volume, uservolume)); add_voice(); bbc_cursor(0); for (;;) { wimpt_complain(os_swi4(Sound_Control, 1, 0x17f, 0x4000, dur/5)); start_time=clock(); bbc_gcol(3, 7); for (s=0; s<1280; s+=2) { bbc_move(s-2, 0); bbc_drawby(0, 1024); bbc_move(s, 0); bbc_drawby(0, 1024); wimpt_complain(os_swi2(OS_Byte,4,1)); if (akbd_pollkey(&i)) { wimpt_complain(os_swi4(Sound_Control, 1, 0, 0x4000, 1)); sx=s; x=640; if (i!=13) for (;;) { if (x!=sx) { bbc_move(sx, 0); bbc_drawby(0, 1024); bbc_move(x, 0); bbc_drawby(0, 1024); sx=x; bbc_tab(0,0); printf("lambda = %f ", ((int)(x*ldif)/1280.0+(int)lmin)/65536.0); } if (akbd_pollkey(&i)) { if (i==136 && x>0) x-=akbd_pollsh()?2:10; if (i==137 && x<1278) x+=akbd_pollsh()?2:10; if (i!=136 && i!=137) { bbc_move(sx, 0); bbc_drawby(0, 1024); bbc_tab(0,0); printf(" "); break; } } } break; } else i=0; for (; clock()-start_time < dur*s/1280; ); } if (s==1280) { bbc_move(s-2, 0); bbc_drawby(0, 1024); } if (i==13) break; } restore(); if (wave_base) free(wave_base); } return 0; } ��Demo1 � i |��~� F����|N� � >Demo1 � .� Demo of how to add a new voice generator (0� Mostly copyright Acorn (see PRM 4.74-4.76) 2� <<� NB Strongly recommend you connect the headphone socket F<� on the computer to a hi-fi amplifier or at the very P'� least to a pair of headphones. Z>� The computer's own internal speaker/s are poor, quiet d7� and don't reproduce low frequency sounds well. n� x: � � WaveTable% 255, Code% 4095 �: �.� First we build our sample at full volume �(ș "Sound_Volume", 127 � UserVolume% �� s%=0 � 255 �A ș "Sound_SoundLog", &7fffffff*�(2*�*s%/256) � WaveTable%?s% �� �"ș "Sound_Volume", UserVolume% �: �� pass%=0 � 2 � 2 �P%=Code% �[ OPT pass% � : .VoiceBase% B Fill% B Fill% " B GateOn% , B GateOff% 6 B Instance% @ LDMFD 13!, {PC} J LDMFD 13!, {PC} T# EQUD VoiceName%-VoiceBase% ^.VoiceName% h EQUS "WaveVoice" r EQUB 0 | ALIGN � : �.LogAmpPtr% � EQUD 0 �.WaveBase% � EQUD WaveTable% � : �2 : ;instantiation code - �E : ;called when voice attached to a channel �- : ;SVC mode in use �B : ; r0 is physical channel # - 1 (0-7) �.Instance% �A STMFD 13!, {0-4} ;all we do is note where the log amp �F MOV 0, #0 ;table is for use by buffer fill routines MOV 1, #0 MOV 2, #0 MOV 3, #0 & MOV 4, #0 0 SWI "XSound_Configure" : LDRVC 0, [3, #12] DF STRVC 0, LogAmpPtr% ;ptr to volume scaled log amplitude table ND STRVS 0, [13] ;scaling log channel amp by overall vol X LDMFD 13!, {0-4, PC} b : l4 : ;buffer fill routines - vD : ;code must be re-entrant & is called in �> : ;IRQ mode with interrupts enabled �4 : ;(hence r14 not usable) �. : ; r0-r8 available �. : ; r9 is SCCB ptr �7 : ; r10 DMA buffer limit + 1 �A : ; r11 DMA buffer interleaf increment �6 : ; r12 DMA buffer base ptr �5 : ; r13 Sound system stack � : �@.GateOn% ;called when a sound is initialised � LDR 0, WaveBase% �2 STR 0, [9, #16] ;set up as work reg 5 � LDR 0, LogAmpPtr% 2 STR 0, [9, #20] ;set up as work reg 6 : E.Fill% ;called during sounding or when starting 2 LDMIA 9, {1-6} ;a new sound smoothly * � 1, 1, #&7f 4F ; r1 log amp (0-127), r2 pitch phase acc >? ; r3 timbre phase acc, r4 duration HE ; r5 wavetable base, r6 amp table base RD ;convert r1 -> VIDC format log amp \D ;(has sign bit in b0) and then get fC LDRB 1, [6, 1, LSL #1] ;log amp scaled by overall volume p9 MOV 1, 1, LSR #1 ;now move sign bit back z RSB 1, 1, #127 �.FillLoop% �9 ADD 2, 2, 2, LSL #16 ;advance waveform phase �2 LDRB 0, [5, 2, LSR #24] ;get wave sample �E SUBS 0, 0, 1, LSL #1 ;scale amp by channel & overall vol �8 MOVMI 0, #0 ;correct for underflow �2 STRB 0, [12], 11 ;generate output �; ADD 2, 2, 2, LSL #16 ;repeat in line once more � LDRB 0, [5, 2, LSR #24] � SUBS 0, 0, 1, LSL #1 � MOVMI 0, #0 � STRB 0, [12], 11 � CMP 12, 10 �: BLT FillLoop% ;loop if not buffer full : ; SUBS 4, 4, #1 ;decrement centisec count > STMIB 9, {2-5} ;save registers back to SCCB $F MOVPL 0, #%00001000 ;voice active if still duration left .3 MOVMI 0, #%00000010 ;else force flush 8 LDMFD 13!, {PC} B : LC.GateOff% ;called to end sounding of a note V MOV 0, #0 `.FlushLoop% j STRB 0, [12], 11 t STRB 0, [12], 11 ~ CMP 12, 10 � BLT FlushLoop% �D MOV 0, #%00000001 ;set flag to flush one more buffer � LDMFD 13!, {PC} �] �� �: �� OldVoice%(8) �3ș "Sound_InstallVoice", VoiceBase%,0 � ,Voice% �� v%=1 � 8 �8 ș "Sound_AttachVoice", v%, Voice% � ,OldVoice%(v%) �� �: � � �RestoreSound:� : ș "Sound_Configure", 8 *Voices (� 1, &17F, 53, 10 24�''"any key to make a noise, <ESCAPE> to finish" <: FC%=1 P� Z K%=�(1) d � K%>0 � n � �K%;" "; x � C%, &17F, K%, 100 � C%+=1:� C%>8 C%=1 � � �� 0 �: �� �RestoreSound � � � � � �:� � �# ș "Sound_RemoveVoice",,Voice% � � v%=1 � 8 �/ ș "Sound_AttachVoice", v%, OldVoice%(v%) � � �ș "Sound_Configure", 1 �*Voices �'' � ��Demo2 � n �e�t� F���2��� � �mode : � ( � "lambda min (0-4)";lmin 2 � "lambda max (0-4)";lmax < : F x=0.5 P l=lmax Z xmin=1:xmax=0 d � c%=1 � 100 n x=l*x*(1-x) x � � � c%=1 � 100 � x=l*x*(1-x) � � x<xmin xmin=x � � x>xmax xmax=x � � � linc=(lmax-lmin)/1280 � lscale=1280/(lmax-lmin) � � xmax=xmin xmin=0:xmax=1 � xscale=1024/(xmax-xmin) � : � � � � l=lmin � lmax � linc � u=(l-lmin)*lscale x=0.5 � c%=1 � 100 x=l*x*(1-x) " � , � c%=1 � 100 6 x=l*x*(1-x) @ � 69, u, (x-xmin)*xscale J � T � ^� � h: r� |: �� �mode �� v% �ș 6,161,133 � ,,v% �v% = v%/4 � 3 �� (v%=0 � v%=2) � =12 �=20 ��Demo3 OV � �ROV F����.�� � � � �a$ � �,� 4 "