void ditherAndClamp(int32_t* out, const int32_t *sums, size_t c) { size_t i; for (i=0 ; i<c ; i++) { int32_t l = *sums++; int32_t r = *sums++; int32_t nl = l >> 12; int32_t nr = r >> 12; l = clamp16(nl); r = clamp16(nr); *out++ = (r<<16) | (l & 0xFFFF); } }
void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; int32_t hist1 = stream->adpcm_history1_16; uint32_t step_size = stream->adpcm_step_index; for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { int sample_nibble = ( (unsigned)read_8bit(stream->offset+i/2,stream->streamfile) >> (i&1?4:0) )&0xf; int32_t sample_delta = (int32_t)step_size * scale_delta[sample_nibble]; int32_t new_sample; new_sample = hist1 + sample_delta/8; outbuf[sample_count] = clamp16(new_sample); hist1 = outbuf[sample_count]; step_size = (step_size * scale_step[sample_nibble])/0x100; if (step_size < 0x7f) step_size = 0x7f; if (step_size > 0x6000) step_size = 0x6000; } stream->adpcm_history1_16 = hist1; stream->adpcm_step_index = step_size; }
static inline int getInt(int y, int u, int v) { int i; int yc=298 * (y-16)+128; u-=128; v-=128; i= clamp(( yc + 409 * v ) >> 8);//&0xff; i|=clamp8(( yc - 100 * u - 208 * v ));//&0xff00; i|=clamp16(( yc + 516 * u )<<8);//&0xff0000; return i;//(int)(byte)(r&0xff)|((int)((byte)g&0xff)<<8)|((int)((byte)b&0xff)<<16);//(int)((byte)(i&0xff));//(y)|(u<<8)|(v<<16);//i; }
void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) { int i, sample_count; int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE; for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { uint32_t sample_int = read_32bit(stream->offset+i*4,stream->streamfile); float* sample_float; int sample_pcm; sample_float = (float*)&sample_int; sample_pcm = (int)floor((*sample_float) * 32767.f + .5f); outbuf[sample_count] = clamp16(sample_pcm); } }
static inline void getSI(unsigned short &rs, int &ri, int y, int u, int v) { int c1,c2,c3; int yc=298 * (y-16)+128; u-=128; v-=128; c1= clamp(( yc + 409 * v ) >> 8);//&0xff; c2=clamp8(( yc - 100 * u - 208 * v ));//&0xff00; c3=clamp16(( yc + 516 * u )<<8);//&0xff0000; ri=c1|c2|c3; c1>>=3; c2>>=(5); c2&=0x07e0; c3>>=8;//3+2,3+2+3 c3&=0xf800; c3|=(c2|c1); rs=c3; }
void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int32_t hist = stream->adpcm_history1_32; int i; int32_t sample_count; for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { int8_t sample_byte = read_8bit(stream->offset+i*channelspacing,stream->streamfile); int16_t sample; if (!(sample_byte & 1)) hist = 0; sample = hist + squares[sample_byte+128]; hist = outbuf[sample_count] = clamp16(sample); } stream->adpcm_history1_32=hist; }
/* Xilam DERF DPCM for Stupid Invaders (PC), decompiled from the exe */ void decode_derf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i, sample_pos = 0, index; int32_t hist = stream->adpcm_history1_32; off_t frame_offset = stream->offset; /* frame size is 1 */ for(i = first_sample; i < first_sample + samples_to_do; i++) { uint8_t code = (uint8_t)read_8bit(frame_offset+i,stream->streamfile); /* original exe doesn't clamp the index, so presumably codes can't over it */ index = code & 0x7f; if (index > 95) index = 95; if (code & 0x80) hist -= derf_steps[index]; else hist += derf_steps[index]; outbuf[sample_pos] = clamp16(hist); sample_pos += channelspacing; } stream->adpcm_history1_32 = hist; }
void GSDrawScanlineCodeGenerator::ColorTFX() { if(!m_sel.fwrite) { return; } switch(m_sel.tfx) { case TFX_MODULATE: // rbt = rbt.modulate16<1>(rb).clamp8(); modulate16(xmm2, xmm13, 1); clamp16(xmm2, xmm0); break; case TFX_DECAL: break; case TFX_HIGHLIGHT: case TFX_HIGHLIGHT2: // gat = gat.modulate16<1>(ga).add16(af).clamp8().mix16(gat); vmovdqa(xmm1, xmm3); modulate16(xmm3, xmm14, 1); vpshuflw(xmm6, xmm14, _MM_SHUFFLE(3, 3, 1, 1)); vpshufhw(xmm6, xmm6, _MM_SHUFFLE(3, 3, 1, 1)); vpsrlw(xmm6, 7); vpaddw(xmm3, xmm6); clamp16(xmm3, xmm0); mix16(xmm3, xmm1, xmm0); // rbt = rbt.modulate16<1>(rb).add16(af).clamp8(); modulate16(xmm2, xmm13, 1); vpaddw(xmm2, xmm6); clamp16(xmm2, xmm0); break; case TFX_NONE: // rbt = iip ? rb.srl16(7) : rb; if(m_sel.iip) { vpsrlw(xmm2, xmm13, 7); } break; } }
void GSDrawScanlineCodeGenerator::AlphaTFX() { if(!m_sel.fb) { return; } switch(m_sel.tfx) { case TFX_MODULATE: // gat = gat.modulate16<1>(ga).clamp8(); modulate16(xmm3, xmm14, 1); clamp16(xmm3, xmm0); // if(!tcc) gat = gat.mix16(ga.srl16(7)); if(!m_sel.tcc) { vpsrlw(xmm1, xmm14, 7); mix16(xmm3, xmm1, xmm0); } break; case TFX_DECAL: // if(!tcc) gat = gat.mix16(ga.srl16(7)); if(!m_sel.tcc) { vpsrlw(xmm1, xmm14, 7); mix16(xmm3, xmm1, xmm0); } break; case TFX_HIGHLIGHT: // gat = gat.mix16(!tcc ? ga.srl16(7) : gat.addus8(ga.srl16(7))); vpsrlw(xmm1, xmm14, 7); if(m_sel.tcc) { vpaddusb(xmm1, xmm3); } mix16(xmm3, xmm1, xmm0); break; case TFX_HIGHLIGHT2: // if(!tcc) gat = gat.mix16(ga.srl16(7)); if(!m_sel.tcc) { vpsrlw(xmm1, xmm14, 7); mix16(xmm3, xmm1, xmm0); } break; case TFX_NONE: // gat = iip ? ga.srl16(7) : ga; if(m_sel.iip) { vpsrlw(xmm3, xmm14, 7); } break; } // TODO: aa1 }
void GSDrawScanlineCodeGenerator::ColorTFX() { if(!m_sel.fwrite) { return; } switch(m_sel.tfx) { case TFX_MODULATE: // GSVector4i rb = iip ? rbf : m_env.c.rb; // rbt = rbt.modulate16<1>(rb).clamp8(); modulate16<1>(xmm5, xmmword[m_sel.iip ? &m_env.temp.rb : &m_env.c.rb]); clamp16(xmm5, xmm1); break; case TFX_DECAL: break; case TFX_HIGHLIGHT: case TFX_HIGHLIGHT2: if(m_sel.tfx == TFX_HIGHLIGHT2 && m_sel.tcc) { // GSVector4i ga = iip ? gaf : m_env.c.ga; movdqa(xmm2, xmmword[m_sel.iip ? &m_env.temp.ga : &m_env.c.ga]); } // gat = gat.modulate16<1>(ga).add16(af).clamp8().mix16(gat); movdqa(xmm1, xmm6); modulate16<1>(xmm6, xmm2); pshuflw(xmm2, xmm2, _MM_SHUFFLE(3, 3, 1, 1)); pshufhw(xmm2, xmm2, _MM_SHUFFLE(3, 3, 1, 1)); psrlw(xmm2, 7); paddw(xmm6, xmm2); clamp16(xmm6, xmm0); mix16(xmm6, xmm1, xmm0); // GSVector4i rb = iip ? rbf : m_env.c.rb; // rbt = rbt.modulate16<1>(rb).add16(af).clamp8(); modulate16<1>(xmm5, xmmword[m_sel.iip ? &m_env.temp.rb : &m_env.c.rb]); paddw(xmm5, xmm2); clamp16(xmm5, xmm0); break; case TFX_NONE: // rbt = iip ? rb.srl16(7) : rb; if(m_sel.iip) { psrlw(xmm5, 7); } break; } }
void GSDrawScanlineCodeGenerator::AlphaTFX() { if(!m_sel.fb) { return; } switch(m_sel.tfx) { case TFX_MODULATE: // GSVector4i ga = iip ? gaf : m_env.c.ga; movdqa(xmm4, xmmword[m_sel.iip ? &m_env.temp.ga : &m_env.c.ga]); // gat = gat.modulate16<1>(ga).clamp8(); modulate16<1>(xmm6, xmm4); clamp16(xmm6, xmm3); // if(!tcc) gat = gat.mix16(ga.srl16(7)); if(!m_sel.tcc) { psrlw(xmm4, 7); mix16(xmm6, xmm4, xmm3); } break; case TFX_DECAL: // if(!tcc) gat = gat.mix16(ga.srl16(7)); if(!m_sel.tcc) { // GSVector4i ga = iip ? gaf : m_env.c.ga; movdqa(xmm4, xmmword[m_sel.iip ? &m_env.temp.ga : &m_env.c.ga]); psrlw(xmm4, 7); mix16(xmm6, xmm4, xmm3); } break; case TFX_HIGHLIGHT: // GSVector4i ga = iip ? gaf : m_env.c.ga; movdqa(xmm4, xmmword[m_sel.iip ? &m_env.temp.ga : &m_env.c.ga]); movdqa(xmm2, xmm4); // gat = gat.mix16(!tcc ? ga.srl16(7) : gat.addus8(ga.srl16(7))); psrlw(xmm4, 7); if(m_sel.tcc) { paddusb(xmm4, xmm6); } mix16(xmm6, xmm4, xmm3); break; case TFX_HIGHLIGHT2: // if(!tcc) gat = gat.mix16(ga.srl16(7)); if(!m_sel.tcc) { // GSVector4i ga = iip ? gaf : m_env.c.ga; movdqa(xmm4, xmmword[m_sel.iip ? &m_env.temp.ga : &m_env.c.ga]); movdqa(xmm2, xmm4); psrlw(xmm4, 7); mix16(xmm6, xmm4, xmm3); } break; case TFX_NONE: // gat = iip ? ga.srl16(7) : ga; if(m_sel.iip) { psrlw(xmm6, 7); } break; } if(m_sel.aa1) { // gs_user figure 3-2: anti-aliasing after tfx, before tests, modifies alpha // FIXME: bios config screen cubes if(!m_sel.abe) { // a = cov if(m_sel.edge) { movdqa(xmm0, xmmword[&m_env.temp.cov]); } else { pcmpeqd(xmm0, xmm0); psllw(xmm0, 15); psrlw(xmm0, 8); } mix16(xmm6, xmm0, xmm1); } else { // a = a == 0x80 ? cov : a pcmpeqd(xmm0, xmm0); psllw(xmm0, 15); psrlw(xmm0, 8); if(m_sel.edge) { movdqa(xmm1, xmmword[&m_env.temp.cov]); } else { movdqa(xmm1, xmm0); } pcmpeqw(xmm0, xmm6); psrld(xmm0, 16); pslld(xmm0, 16); blend8(xmm6, xmm1); } } }
if (i & 1) {/* odd/even nibble */ scale = byte >> 4; } else { byte = read_8bit(stream->offset+(framesin*16)+2+i/2,stream->streamfile); scale = byte & 0x0f; } if (scale > 7) { /* sign extend */ scale = scale - 16; } sample = (hist1 * HEVAG_coefs[predict_nr][0] + hist2 * HEVAG_coefs[predict_nr][1] + hist3 * HEVAG_coefs[predict_nr][2] + hist4 * HEVAG_coefs[predict_nr][3] ) / 32; sample = (sample + (scale << (20 - shift)) + 128) >> 8; } outbuf[sample_count] = clamp16(sample); hist4 = hist3; hist3 = hist2; hist2 = hist1; hist1 = sample; } stream->adpcm_history1_32 = hist1; stream->adpcm_history2_32 = hist2; stream->adpcm_history3_32 = hist3; stream->adpcm_history4_32 = hist4; }
void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do) { VGMSTREAMCHANNEL *ch1,*ch2; int i; int framesin; STREAMFILE *streamfile; off_t offset; framesin = first_sample/get_vgmstream_samples_per_frame(vgmstream); first_sample = first_sample%get_vgmstream_samples_per_frame(vgmstream); ch1 = &vgmstream->ch[0]; ch2 = &vgmstream->ch[1]; streamfile = ch1->streamfile; offset = ch1->offset+framesin*get_vgmstream_frame_size(vgmstream); if (first_sample==0) { ch1->adpcm_coef[0] = ADPCMCoeffs[read_8bit(offset,streamfile)][0]; ch1->adpcm_coef[1] = ADPCMCoeffs[read_8bit(offset,streamfile)][1]; ch2->adpcm_coef[0] = ADPCMCoeffs[read_8bit(offset+1,streamfile)][0]; ch2->adpcm_coef[1] = ADPCMCoeffs[read_8bit(offset+1,streamfile)][1]; ch1->adpcm_scale = read_16bitLE(offset+2,streamfile); ch2->adpcm_scale = read_16bitLE(offset+4,streamfile); ch1->adpcm_history1_16 = read_16bitLE(offset+6,streamfile); ch2->adpcm_history1_16 = read_16bitLE(offset+8,streamfile); ch1->adpcm_history2_16 = read_16bitLE(offset+10,streamfile); ch2->adpcm_history2_16 = read_16bitLE(offset+12,streamfile); outbuf[0] = ch1->adpcm_history2_16; outbuf[1] = ch2->adpcm_history2_16; outbuf+=2; first_sample++; samples_to_do--; } if (first_sample==1 && samples_to_do > 0) { outbuf[0] = ch1->adpcm_history1_16; outbuf[1] = ch2->adpcm_history1_16; outbuf+=2; first_sample++; samples_to_do--; } for (i=first_sample; i<first_sample+samples_to_do; i++) { int j; for (j=0; j<2; j++) { VGMSTREAMCHANNEL *ch = &vgmstream->ch[j]; int sample_nibble = (j == 0 ? get_high_nibble_signed(read_8bit(offset+14+i-2,streamfile)) : get_low_nibble_signed(read_8bit(offset+14+i-2,streamfile)) ); int32_t hist1,hist2; int32_t predicted; hist1 = ch->adpcm_history1_16; hist2 = ch->adpcm_history2_16; predicted = hist1 * ch->adpcm_coef[0] + hist2 * ch->adpcm_coef[1]; predicted /= 256; predicted += sample_nibble*ch->adpcm_scale; outbuf[0] = clamp16(predicted); ch->adpcm_history2_16 = ch->adpcm_history1_16; ch->adpcm_history1_16 = outbuf[0]; ch->adpcm_scale = (ADPCMTable[sample_nibble&0xf] * ch->adpcm_scale) / 256; if (ch->adpcm_scale < 0x10) ch->adpcm_scale = 0x10; outbuf++; } } }