static void do_vis(char *data, int nch, int resolution, int position, unsigned samples) { static char vis_buffer[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS]; char *ptr; int size, count; /* * Winamp visuals may have problems accepting sample sizes larger than * 16 bits, so we reduce the sample size here if necessary. */ switch(resolution) { case 32: case 24: size = resolution / 8; count = samples * nch; data += size - 1; ptr = vis_buffer; while(count--) { *ptr++ = data[0] ^ 0x80; data += size; } data = vis_buffer; resolution = 8; /* fall through */ case 16: case 8: mod_.SAAddPCMData(data, nch, resolution, position); mod_.VSAAddPCMData(data, nch, resolution, position); } }
void writeSound(void) { int ret = soundBufferLen; //int i; while (mod.outMod->CanWrite() < ((ret*sndNumChannels*(sndBitsPerSample/8))<<(mod.dsp_isactive()?1:0))) Sleep(50); mod.SAAddPCMData((char *)soundFinalWave,sndNumChannels,sndBitsPerSample,decode_pos_ms); mod.VSAAddPCMData((char *)soundFinalWave,sndNumChannels,sndBitsPerSample,decode_pos_ms); decode_pos_ms += (ret/(2*sndNumChannels) * 1000) / (float)sndSamplesPerSec; if (mod.dsp_isactive()) ret=mod.dsp_dosamples((short *)soundFinalWave,ret/sndNumChannels/(sndBitsPerSample/8),sndBitsPerSample,sndNumChannels,sndSamplesPerSec)*(sndNumChannels*(sndBitsPerSample/8)); //if(soundFinalWave[0]==0&&soundFinalWave[1]==0&&soundFinalWave[2]==0&&soundFinalWave[3]==0) // DisplayError("%.2X%.2X%.2X%.2X - %d", soundFinalWave[0],soundFinalWave[1],soundFinalWave[2],soundFinalWave[3],ret); mod.outMod->Write((char *)&soundFinalWave,ret); if (seek_needed != -1) //if a seek is initiated { mod.outMod->Flush((long)decode_pos_ms); if (seek_needed < decode_pos_ms) //if we are asked to seek backwards. we have to start from the beginning { GSFClose(); GSFRun(lastfn); decode_pos_ms = 0; } } }
DWORD WINAPI __stdcall DecodeThread(void *b) { int done=0; while (! *((int *)b) ) { if (seek_needed != -1) { //DisplayError("seek to %d",seek_needed); if (decode_pos_ms>seek_needed) { if (!InitADPFILE(NULL, &cubefile) || !InitADXFILE(NULL, &cubefile) || !InitDSPFILE(NULL, &cubefile)); decode_pos_ms=-1; // -1 ms, force it to work even if we want to seek to 0 } while (decode_pos_ms<seek_needed && ! *((int *)b)) { get_576_samples((short*)sample_buffer); mod.outMod->Flush((int)decode_pos_ms); decode_pos_ms+=(576.0*1000.0)/(double)cubefile.ch[0].sample_rate; } seek_needed=-1; } if (done) { mod.outMod->CanWrite(); if (!mod.outMod->IsPlaying()) { PostMessage(mod.hMainWindow,WM_WA_MPEG_EOF,0,0); return 0; } Sleep(10); } else if (mod.outMod->CanWrite() >= ((576*cubefile.NCH*(BPS/8))<<(mod.dsp_isactive()?1:0))) { int l=576*cubefile.NCH*(BPS/8); l=get_576_samples((short*)sample_buffer); if (!l) { done=1; } else { if (l==576*cubefile.NCH*(BPS/8)) { mod.SAAddPCMData((char *)sample_buffer,cubefile.NCH,BPS,mod.outMod->GetWrittenTime()); mod.VSAAddPCMData((char *)sample_buffer,cubefile.NCH,BPS,mod.outMod->GetWrittenTime()); } decode_pos_ms+=(576.0*1000.0)/(double)cubefile.ch[0].sample_rate; if (mod.dsp_isactive()) l=mod.dsp_dosamples((short *)sample_buffer,l/cubefile.NCH/(BPS/8),BPS,cubefile.NCH,cubefile.ch[0].sample_rate)*(cubefile.NCH*(BPS/8)); mod.outMod->Write(sample_buffer,l); } } else Sleep(20); } return 0; }
static DWORD WINAPI playThread(LPVOID dummy) { while (thread_run) { static #if BITS_PER_SAMPLE == 8 byte #else short #endif buffer[BUFFERED_BLOCKS * 2 #if SUPPORT_EQUALIZER * 2 #endif ]; int buffered_bytes = BUFFERED_BLOCKS * channels * (BITS_PER_SAMPLE / 8); if (seek_needed >= 0) { mod.outMod->Flush(seek_needed); ASAP_Seek(&asap, seek_needed); seek_needed = -1; } if (mod.outMod->CanWrite() >= buffered_bytes #if SUPPORT_EQUALIZER << mod.dsp_isactive() #endif ) { int t; buffered_bytes = ASAP_Generate(&asap, buffer, buffered_bytes, BITS_PER_SAMPLE); if (buffered_bytes <= 0) { mod.outMod->CanWrite(); if (!mod.outMod->IsPlaying()) { PostMessage(mod.hMainWindow, WM_WA_MPEG_EOF, 0, 0); return 0; } Sleep(10); continue; } t = mod.outMod->GetWrittenTime(); mod.SAAddPCMData(buffer, channels, BITS_PER_SAMPLE, t); mod.VSAAddPCMData(buffer, channels, BITS_PER_SAMPLE, t); #if SUPPORT_EQUALIZER t = buffered_bytes / (channels * (BITS_PER_SAMPLE / 8)); t = mod.dsp_dosamples((short *) buffer, t, BITS_PER_SAMPLE, channels, ASAP_SAMPLE_RATE); t *= channels * (BITS_PER_SAMPLE / 8); mod.outMod->Write((char *) buffer, t); #else mod.outMod->Write((char *) buffer, buffered_bytes); #endif } else Sleep(20); } return 0; }
DWORD WINAPI PlayThread(void *b) { int done=0; int l; int decoded_frames=0; int br_calc_frames=0; int br_bytes_consumed=0; unsigned long bytesconsumed; PlayThreadAlive = 1; last_frame = 0; while (! *((int *)b) ) { if (seek_needed != -1) { int seconds; // Round off to a second seconds = seek_needed - (seek_needed%1000); mod.outMod->Flush(decode_pos_ms); aac_seek(seconds, seek_table); decode_pos_ms = seconds; seek_needed = -1; decoded_frames = 0; br_calc_frames = 0; br_bytes_consumed = 0; } if (done) { mod.outMod->CanWrite(); if (!mod.outMod->IsPlaying()) { PostMessage(mod.hMainWindow,WM_WA_AAC_EOF,0,0); PlayThreadAlive = 0; return 0; } Sleep(10); } //assume that max channels is 2. else if (mod.outMod->CanWrite() >= ((1024*file_info.channels*sizeof(short))<<(mod.dsp_isactive()?1:0))) { if(last_frame) { done=1; } else { if (current_file_mode) bytesconsumed = PlayThread_memmap(); else bytesconsumed = PlayThread_file(); decoded_frames++; br_calc_frames++; br_bytes_consumed += bytesconsumed; /* Update the variable bitrate about every second */ if(m_variable_bitrate_display && br_calc_frames == 43) { int br; br = (int)((br_bytes_consumed * 8) / (decoded_frames / 43.07)); mod.SetInfo(br/1000, file_info.sampling_rate/1000, file_info.channels, 1); br_calc_frames = 0; } if (!killPlayThread && (frameInfo.samples > 0)) { mod.SAAddPCMData(sample_buffer,file_info.channels, 16, decode_pos_ms); mod.VSAAddPCMData(sample_buffer,file_info.channels, 16, decode_pos_ms); decode_pos_ms+=(1024*1000)/file_info.sampling_rate; if (mod.dsp_isactive()) l=mod.dsp_dosamples((short *)sample_buffer,frameInfo.samples*sizeof(short)/file_info.channels/(16/8),16,file_info.channels,file_info.sampling_rate)*(file_info.channels*(16/8)); else l = frameInfo.samples*sizeof(short); mod.outMod->Write(sample_buffer, l); } } } else { Sleep(10); } } if(seek_table) { free(seek_table); seek_table = NULL; seek_table_length = 0; } PlayThreadAlive = 0; return 0; }
DWORD WINAPI DecodeThread(LPVOID b) { int done=0; // set to TRUE if decoding has finished while (!killDecodeThread) { if (seek_needed != -1) // seek is needed. { int offs; decode_pos_ms = seek_needed; seek_needed=-1; done=0; mod.outMod->Flush(decode_pos_ms); // flush output device and set // output position to the seek position offs = MulDiv(decode_pos_ms,SAMPLERATE,1000); // decode_pos_ms*SAMPLERATE/1000 SetFilePointer(input_file,offs*NCH*(BPS/8),NULL,FILE_BEGIN); // seek! } if (done) // done was set to TRUE during decoding, signaling eof { mod.outMod->CanWrite(); // some output drivers need CanWrite // to be called on a regular basis. if (!mod.outMod->IsPlaying()) { // we're done playing, so tell Winamp and quit the thread. PostMessage(mod.hMainWindow,WM_WA_MPEG_EOF,0,0); return 0; // quit thread } Sleep(10); // give a little CPU time back to the system. } else if (mod.outMod->CanWrite() >= ((576*NCH*(BPS/8))*(mod.dsp_isactive()?2:1))) // CanWrite() returns the number of bytes you can write, so we check that // to the block size. the reason we multiply the block size by two if // mod.dsp_isactive() is that DSP plug-ins can change it by up to a // factor of two (for tempo adjustment). { int l=576*NCH*(BPS/8); // block length in bytes static char sample_buffer[576*NCH*(BPS/8)*2]; // sample buffer. twice as // big as the blocksize l=get_576_samples(sample_buffer); // retrieve samples if (!l) // no samples means we're at eof { done=1; } else // we got samples! { // give the samples to the vis subsystems mod.SAAddPCMData((char *)sample_buffer,NCH,BPS,decode_pos_ms); mod.VSAAddPCMData((char *)sample_buffer,NCH,BPS,decode_pos_ms); // adjust decode position variable decode_pos_ms+=(576*1000)/SAMPLERATE; // if we have a DSP plug-in, then call it on our samples if (mod.dsp_isactive()) l=mod.dsp_dosamples( (short *)sample_buffer,l/NCH/(BPS/8),BPS,NCH,SAMPLERATE ) // dsp_dosamples *(NCH*(BPS/8)); // write the pcm data to the output system mod.outMod->Write(sample_buffer,l); } } else Sleep(20); // if we can't write data, wait a little bit. Otherwise, continue // through the loop writing more data (without sleeping) } return 0; }
static DWORD WINAPI DecodeThread( LPVOID ) { MSG msg; PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ); bool eof = false; while ( true ) { bool quit = false; while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { if ( msg.message == WM_QUIT ) { quit = true; } else if ( msg.message == WM_OPENMPT_SEEK ) { double pos_seconds = self->mod->set_position_seconds( msg.lParam * 0.001 ); self->decode_position_frames = (std::int64_t)( pos_seconds * (double)self->samplerate); eof = false; inmod.outMod->Flush( (int)( pos_seconds * 1000.0 ) ); } } if ( quit ) { break; } if ( eof ) { inmod.outMod->CanWrite(); // update output plugin state if ( !inmod.outMod->IsPlaying() ) { PostMessage( inmod.hMainWindow, WM_WA_MPEG_EOF, 0, 0 ); return 0; } Sleep( 10 ); } else { bool dsp_active = inmod.dsp_isactive() ? true : false; if ( inmod.outMod->CanWrite() >= (int)( WINAMP_BUFFER_SIZE_FRAMES * self->channels * sizeof( signed short ) ) * ( dsp_active ? WINAMP_DSP_HEADROOM_FACTOR : 1 ) ) { int frames = 0; switch ( self->channels ) { case 1: frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+0*WINAMP_BUFFER_SIZE_FRAMES ); for ( int frame = 0; frame < frames; frame++ ) { self->interleaved_buffer[frame*1+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame]; } break; case 2: frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+0*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+1*WINAMP_BUFFER_SIZE_FRAMES ); for ( int frame = 0; frame < frames; frame++ ) { self->interleaved_buffer[frame*2+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame]; self->interleaved_buffer[frame*2+1] = self->buffer[1*WINAMP_BUFFER_SIZE_FRAMES+frame]; } break; case 4: frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+0*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+1*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+2*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+3*WINAMP_BUFFER_SIZE_FRAMES ); for ( int frame = 0; frame < frames; frame++ ) { self->interleaved_buffer[frame*4+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame]; self->interleaved_buffer[frame*4+1] = self->buffer[1*WINAMP_BUFFER_SIZE_FRAMES+frame]; self->interleaved_buffer[frame*4+2] = self->buffer[2*WINAMP_BUFFER_SIZE_FRAMES+frame]; self->interleaved_buffer[frame*4+3] = self->buffer[3*WINAMP_BUFFER_SIZE_FRAMES+frame]; } break; } if ( frames == 0 ) { eof = true; } else { self->decode_position_frames += frames; std::int64_t decode_pos_ms = (self->decode_position_frames * 1000 / self->samplerate ); inmod.SAAddPCMData( &( self->interleaved_buffer[0] ), self->channels, BPS, (int)decode_pos_ms ); inmod.VSAAddPCMData( &( self->interleaved_buffer[0] ), self->channels, BPS, (int)decode_pos_ms ); if ( dsp_active ) { frames = inmod.dsp_dosamples( &( self->interleaved_buffer[0] ), frames, BPS, self->channels, self->samplerate ); } int bytes = frames * self->channels * sizeof( signed short ); inmod.outMod->Write( (char*)&( self->interleaved_buffer[0] ), bytes ); } } else { Sleep( 10 ); } } } return 0; }