node newtmp(node ttype, scope v, bool decl){ node tmpsymb; assert(ttype != returns_T && ttype != exits_T); tmpsymb = newsymbol(tmp__S,totype(ttype),NULL, intern_F|tmp_F|defined_F|literal_F); if (decl) push(v->tmpdecls,list(2,declare__S,tmpsymb)); return tmpsymb; }
node newstmp(node ttype, scope v, bool decl){ node tmpsymb; static int count = 0; char buf[20]; tmpsymb = newsymbol(tmp__S,totype(ttype),NULL, intern_F|defined_F|tmp_F); sprintf(buf,"stmp%d_",count++); tmpsymb->body.symbol.Cname = strperm(buf); if (decl) push(v->tmpdecls,list(2,declare__S,tmpsymb)); return tmpsymb; }
static int typeseqno(node t){ assert(istype(t)); return totype(t)->body.type.seqno; }
node type(node e){ /* assume e is checked previously */ /* this returns a unique TYPE */ if (e == NULL) return void_T; again: switch(e->tag) { case position_tag: e = e->body.position.contents; goto again; case symbol_tag: return e->body.symbol.type; case string_const_tag: /* not implemented yet */ return bad_or_undefined_T; case char_const_tag: return char_T; case int_const_tag: return int_T; case double_const_tag: return double_T; case string_tag: assert(FALSE); case unique_string_tag: assert(FALSE); /* was return bad_or_undefined_T; */ case cons_tag: { node h, ht; h = unpos(CAR(e)); if (h->tag == unique_string_tag) { if (h == equalequal__S || h == unequal_S) return bool_T; if (h == cast__S) { assert(istype(CADR(e))); return cadr(e); } if (h == function_S) return type__T; if (h == funcall__S || h == prefix__S || h == infix__S) { return functionrettype(type(CADR(e))); } if (h == take__S) { return membertype(type(CADR(e)),CADDR(e)); } if (h == array_take_S) { return arrayElementType(type(CADR(e))); } if (h == return_S) return returns_T; if (h == exits_S) return exits_T; if (h == Ccode_S) return cadr(e); assert(FALSE); } ht = type(h); if (ht == type__T) return totype(h); if (ht == keyword_T) { node w = ispos(h) ? h->body.position.contents : h; if (w == block__K) return void_T; if (w == blockn__K) { if (length(e) < 2) return void_T; return type(last(e)); } if ( w == object__K || w == tagged_object_K || w == array_K || w == tarray_K || w == or_K) { return type__T; } if (w == label__S) return void_T; if (w == goto__S) return void_T; assert(FALSE); /* there must be some other keywords! */ } ht = ht->body.type.definition; if (iscons(ht)) { if (equal(CAR(ht),function_S)) { assert(FALSE); return caddr(ht); } else assert(FALSE); return NULL; } assert(FALSE); return NULL; } case type_tag: return type__T; } assert(FALSE); return NULL; }
// as determined by the values you specify for fromchannels and tochannels. // however, it is recommended the mixing destination buffer always be stereo, for quality reasons. // PANNING AND VOLUME ADJUSTMENT: // the cached volume levels given are applied to the source audio when mixing. // this automatically includes panning, which applies for every case except (mono to mono) conversion. // CLIPPING: // values exceeding the bounds of the destination bitrate will be clamped to within the valid range. // INTERPOLATION: // this performs linear interpolation of samples. // some games would sound very noticeably wrong otherwise. template<typename fromtype, typename totype, int fromchannels, int tochannels> static void Mix(const unsigned char*__restrict buf, unsigned char*__restrict outbuf, DWORD size, DWORD outSize, bool sizeReachesBufferEnd, Hooks::DirectSound::CachedVolumeAndPan& volumes) { enum { fromshift = (2+sizeof(fromtype)-sizeof(totype))<<3 }; // 16 when both buffers have the same bit/sample... this is for combining differing bitrates enum { maxto = (1<<(8*sizeof(totype)-1))-1 }; // clamping magnitude (127 or 32767) enum { tosignoffset = (totype(-1)<0)?0:-(1<<(8*sizeof(totype)-1)) }; // add this to make numbers in the "to" buffer signed enum { fromsignoffset = (fromtype(-1)<0)?0:-(1<<(8*sizeof(fromtype)-1)) }; // add this to make numbers in the "from" buffer signed enum { toincrement = sizeof(totype) * tochannels }; enum { fromincrement = sizeof(fromtype) * fromchannels }; DWORD frac = 0; // amount of next sample to use, out of 1024 (for linear interpolation) DWORD fracnumer = (size*(toincrement<<10)); DWORD fracincrement = fracnumer / outSize; // unfortunately needs to be very exact (can't drift even by 1 or clicking becomes audible), so we also need: DWORD fracErrorIncrement = fracnumer % outSize; DWORD fracError = 0; DWORD offsetRemainder = 0; DWORD inOffset = 0; for(DWORD i = 0; i < outSize; outbuf += toincrement, i += toincrement) {