⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 waveout_win32.c

📁 betaplayer的源码 tcpmp的老版本
💻 C
📖 第 1 页 / 共 2 页
字号:
			ReleaseBuffer(p,Buffer,1);
		InterlockedDecrement(&p->Waiting);

		//DEBUG_MSG1(-1,T("WAVEOUT Waiting %d"),p->Waiting);
    }
}

static void UpdatePCM(waveout* p,const audio* InputFormat)
{
	p->SpeedTime = p->Speed;
	p->SpeedTime.Num *= TICKSPERSEC;
	p->SpeedTime.Den *= GetTimeFreq();

	p->BufferScaledTime = Scale(TICKSPERSEC,p->Speed.Num*p->BufferLength,p->Speed.Den*p->Format.nAvgBytesPerSec);
	if (p->BufferLength)
		p->BufferScaledAdjust = (p->BufferScaledTime*4096) / p->BufferLength;
	else
		p->BufferScaledAdjust = 0;
	if (!p->Speed.Num)
		p->PCMSpeed = SPEED_ONE;
	else
		p->PCMSpeed = Scale(SPEED_ONE,p->Speed.Num,p->Speed.Den);
	p->AdjustedRate = Scale(p->OutputFormat.SampleRate,p->Speed.Den,p->Speed.Num);

	if (p->Swap)
		p->OutputFormat.Flags |= PCM_SWAPEDSTEREO;
	else
		p->OutputFormat.Flags &= ~PCM_SWAPEDSTEREO;

	PCMRelease(p->PCM);
	p->PCM = PCMCreate(&p->OutputFormat,InputFormat,p->Dither,p->SoftwareVolume);
}

static int UpdateBufferTime(waveout* p)
{
	p->BufferLimit = Scale(p->BufferTime,p->Format.nAvgBytesPerSec,p->BufferLength*TICKSPERSEC);
	p->BufferLimitFull = p->BufferLimit;
	return ERR_NONE;
}

static bool_t FreeBuffers(waveout* p);

static int SetFormat(waveout* p, const audio* Format, bool_t KeepHandle )
{
	Reset(p);

	FreeBuffers(p);

	if (p->Handle && !KeepHandle)
	{
		waveOutClose(p->Handle);
		p->Handle = NULL;
	}

	p->TotalBytes = 0;
	p->BytesPerSample = 1;

	memset(&p->InputFormat,0,sizeof(audio));

	if (Format)
	{
		if (!p->Handle || !KeepHandle)
		{
			MMRESULT MMResult;
			int Try;

			if (Format->Format != AUDIOFMT_PCM) 
				return ERR_INVALID_DATA;

			if (Format->Channels == 0)
				return ERR_NONE;

			p->OutputFormat = *Format;
			p->OutputFormat.Flags = 0;
			p->Dither = 0;

			if (p->Stereo>0)
			{
				p->OutputFormat.Channels = 1;
				p->OutputFormat.Flags |= (p->Stereo==1) ? PCM_ONLY_LEFT:PCM_ONLY_RIGHT;
			}

			switch (p->Quality)
			{
			case 0: // low quality for very poor devices
				p->OutputFormat.Bits = 8;
				p->OutputFormat.FracBits = 7;
				p->OutputFormat.Channels = 1;
				p->OutputFormat.SampleRate = 22050;
				break;

			case 1: // no dither and only standard samplerate
				p->OutputFormat.Bits = 16;
				p->OutputFormat.FracBits = 15;
				if (p->OutputFormat.SampleRate >= 44100)
					p->OutputFormat.SampleRate = 44100;
				else
					p->OutputFormat.SampleRate = 22050;
				break;

			default:
			case 2: // original samplerate 
				p->OutputFormat.Bits = 16;
				p->OutputFormat.FracBits = 15;
				p->Dither = 1;
				break;
			}

			Try = 0;
			do
			{
				if (p->OutputFormat.Bits <= 8)
					p->OutputFormat.Flags |= PCM_UNSIGNED;

				p->Format.wFormatTag = WAVE_FORMAT_PCM;
				p->Format.nChannels = (WORD)p->OutputFormat.Channels;
				p->Format.nSamplesPerSec = p->OutputFormat.SampleRate;
				p->Format.wBitsPerSample = (WORD)p->OutputFormat.Bits;
				p->Format.nBlockAlign = (WORD)((p->Format.nChannels * p->Format.wBitsPerSample) >> 3);
				p->Format.nAvgBytesPerSec = p->Format.nSamplesPerSec * p->Format.nBlockAlign;
				p->Format.cbSize = 0;

				MMResult = waveOutOpen( &p->Handle, WAVE_MAPPER, &p->Format,(DWORD)WaveProc,
										(DWORD)p,CALLBACK_FUNCTION);

				if (MMResult==WAVERR_BADFORMAT)
				{
					++Try;
					if (Try==1)
					{
						if (p->OutputFormat.SampleRate > 35000)
							p->OutputFormat.SampleRate = 44100;
						else
							++Try;
					}
					if (Try==2)
					{
						if (p->OutputFormat.SampleRate != 22050)
							p->OutputFormat.SampleRate = 22050;
						else
							++Try;
					}
					if (Try==3)
					{
						if (p->OutputFormat.Channels > 1)
							p->OutputFormat.Channels = 1;
						else
							++Try;
					}
					if (Try==4)
					{
						if (p->OutputFormat.Bits != 8)
						{
							p->OutputFormat.Bits = 8;
							p->OutputFormat.FracBits = 7;
						}
						else
							++Try;
					}
					if (Try==5)
						break;
				}
			}
			while (MMResult==WAVERR_BADFORMAT);
		}

		if (p->Handle)
		{
			p->TimeRef = GetTimeTick();
			p->InputFormat = *Format;

			p->BufferLength = 4096;
			if (p->Format.nAvgBytesPerSec > 65536)
				p->BufferLength *= 2;
			if (p->Format.nAvgBytesPerSec > 2*65536)
				p->BufferLength *= 2;
			UpdateBufferTime(p);
		
			p->FillPos = p->BufferLength;
			p->VolumeRamp = 0;
			p->BytesPerSample = p->InputFormat.Bits >> 3;
			if (!(p->InputFormat.Flags & PCM_PLANES))
				p->BytesPerSample *= p->InputFormat.Channels;

			UpdatePCM(p,&p->InputFormat);
			Reset(p);
		}
		else
		{
			NodeError(&p->VMT,ERR_ID,ERR_DEVICE_ERROR);
			return ERR_DEVICE_ERROR;
		}
	}
		
	return ERR_NONE;
}

static int SetInput(waveout* p,const packet* Packet)
{
	if (!p->Handle)
	{
		// act as a null device
		if (Packet->CurrTime != -1 && (Packet->RefTime > Packet->CurrTime + SHOWAHEAD))
			return ERR_BUFFER_FULL;
		else
			return ERR_NONE;
	}

	if (p->Speed.Num==0) // benchmark mode (auto adjust speed)
	{
		int Pos = p->BenchWaitPos;
		int OldSum;
		int Speed;

		if (p->Play)
		{
			while (Packet->Length > p->BenchAvgLimit)
				UpdateBenchAvg(p);
	
			p->BenchCurrSum -= p->BenchWait[Pos];
			p->BenchWait[Pos] = (p->Waiting * p->BufferLength) >> 12;
			p->BenchCurrSum += p->BenchWait[Pos];

			OldSum = p->BenchSum[Pos];
			p->BenchSum[Pos] = p->BenchCurrSum;

			if (++Pos == BENCH_SIZE)
				Pos = 0;

			p->BenchWaitPos = Pos;

			if (p->BenchCurrSum < 2*BENCH_SIZE*p->BenchAvg)
				Speed = (p->BenchCurrSum+1) * p->BenchSpeedAvg;
			else
				Speed = 2*SPEED_ONE+(p->BenchCurrSum-2*BENCH_SIZE*p->BenchAvg+1) * 4*p->BenchSpeedAvg;

			Speed -= p->BenchAdj*(p->BenchCurrSum - OldSum);

			if (p->Waiting < 3)
				Speed -= SPEED_ONE/5;
		}
		else
			Speed = SPEED_ONE;

		//DEBUG_MSG3(-1,T("Audio speed:%d length:%d (wait:%d)"),Speed,Packet->Length,p->Waiting);
		return Send(p,Packet->Data,Packet->Length,Packet->RefTime,Packet->CurrTime,Speed);
	}

	if (Packet->DropLevel)
		return ERR_NONE;

	if (p->Used >= p->BufferLimit)
	{
		Write(p,Packet->CurrTime);
		return ERR_BUFFER_FULL;
	}

	DEBUG_MSG3(DEBUG_AUDIO,T("Waveout reftime:%d used:%d waiting:%d"),Packet->RefTime,p->Used,p->Waiting);
	return Send(p,Packet->Data,Packet->Length,Packet->RefTime,Packet->CurrTime,p->PCMSpeed);
}

static int Update(waveout* p)
{
	buffer *OldFirst;
	buffer *OldLast;
	audio OldFormat;
	buffer* OldBuffers;
	buffer* OldFill;
	int OldFillPos; 
	int OldUsed;
	bool_t OldVolume;
	buffer *Buffer,*Next;

	EnterCriticalSection(&p->Section);

	OldVolume = p->SoftwareVolume;
	OldUsed = p->Used;
	OldFirst = p->FreeFirst;
	OldLast = p->FreeLast;
	OldFormat = p->OutputFormat;
	OldFormat.SampleRate = p->AdjustedRate;

	OldFill = p->FillFirst;
	OldFillPos = p->FillPos;

	p->FillFirst = NULL;
	p->FillLast = NULL;
	p->FillPos = p->BufferLength;
	p->FreeFirst = NULL;
	p->FreeLast = NULL;

	LeaveCriticalSection(&p->Section);

	Reset(p);

	OldBuffers = p->FreeFirst;
	if (p->FreeLast)
		p->FreeLast->Next = OldFill;
	else
		OldBuffers = OldFill;

	p->SoftwareVolume = 0;
	p->Used = OldUsed;
	p->FreeFirst = OldFirst;
	p->FreeLast = OldLast;

	// setup temporary format
	UpdatePCM(p,&OldFormat);

	for (Buffer=OldBuffers;Buffer;Buffer=Next)
	{
		Next = Buffer->Next;
		Send(p,Buffer->Planes,Next ? p->BufferLength:OldFillPos,Buffer->RefTime,-1,p->PCMSpeed);
		ReleaseBuffer(p,Buffer,0);
	}

	p->SoftwareVolume = OldVolume;
	UpdatePCM(p,&p->InputFormat);
	return ERR_NONE;
}

static bool_t FreeBuffers(waveout* p)
{
	buffer** Ptr;
	buffer* Buffer;
	bool_t Changed = 0;

	while (p->FreeFirst)
	{
		Buffer = p->FreeFirst;
		p->FreeFirst = Buffer->Next;

		// remove from global chain
		Ptr = &p->Buffers;
		while (*Ptr && *Ptr != Buffer)
			Ptr = &(*Ptr)->GlobalNext;
		if (*Ptr == Buffer)
			*Ptr = Buffer->Next;

		waveOutUnprepareHeader( p->Handle, &Buffer->Head, sizeof(WAVEHDR) );
		FreeBlock(Buffer->Buffer);
		Free(Buffer);
		Changed = 1;
	}
	p->FreeLast = NULL;

	return Changed;
}

static int Hibernate(waveout* p,int Mode)
{
	bool_t Changed = 0;

	EnterCriticalSection(&p->Section);
	Changed = FreeBuffers(p);
	LeaveCriticalSection(&p->Section);

	return Changed ? ERR_NONE : ERR_OUT_OF_MEMORY;
}

static int UpdateFormat(waveout* p,bool_t KeepFormat)
{
	audio SaveFormat = p->InputFormat;
	return SetFormat(p,&SaveFormat,KeepFormat);
}

static int UpdatePlay(waveout* p)
{
	if (p->Play)
	{
		p->TimeRef = GetTimeTick();
		if (p->Handle)
			Write(p,p->Tick);
	}
	else
	{
		if (!p->Waiting)
			p->Tick += Scale(GetTimeTick()-p->TimeRef,p->SpeedTime.Num,p->SpeedTime.Den);
		else
		if (p->Handle)
		{
			p->Pausing = &p->FillFirst;
			waveOutReset(p->Handle);
			p->Pausing = NULL;
			p->FillLast = p->FillFirst;
			if (p->FillLast)
				while (p->FillLast->Next) p->FillLast = p->FillLast->Next;

		}
	}
	return ERR_NONE;
}

static int SetVolume(waveout* p)
{
	if (p->Mute)
		waveOutSetVolume(NULL,0);
	else
		waveOutSetVolume(NULL,0x10001 * ((0xFFFF * p->Volume) / 100));
	return ERR_NONE;
}

static int Set(waveout* p, int No, const void* Data, int Size )
{
	int Result = ERR_INVALID_PARAM;
	switch (No)
	{
	case AOUT_INPUT|PACKET_FORMAT:
		if (!Size || Size == sizeof(audio))
		{
			if (!Size) Data = NULL;
			Result = SetFormat(p,(const audio*)Data,0);
		}
		break;
	case AOUT_INPUT:
		if (Size == sizeof(packet))
			Result = SetInput(p,(const packet*)Data);
		break;

	case AOUT_VOLUME: 
		if (Size==sizeof(int))
		{
			if (p->SoftwareVolume)
			{
				SetSoftVolume(*(int*)Data);
				Result = UpdateVolumeSoftLog(p);
			}
			else
			{
				p->Volume = *(int*)Data;
				Result = SetVolume(p);
			}
		}
		break;

	case AOUT_MUTE:
		if (Size==sizeof(bool_t))
		{
			if (!p->Mute)
				GetVolume(p); // save old volume to p->Volume
			p->Mute = *(bool_t*)Data;
			Result = SetVolume(p);
		}
		break;

	case AOUT_SWAP: SETVALUECMP(p->Swap,bool_t,Update(p),EqBool); break;
	case AOUT_STEREO: SETVALUECMP(p->Stereo,int,UpdateFormat(p,0),EqInt); break; 
	case AOUT_QUALITY: SETVALUECMP(p->Quality,int,UpdateFormat(p,0),EqInt); break; 
	case AOUT_BUFFER: SETVALUE(p->BufferTime,tick_t,UpdateBufferTime(p)); break;

	case NODE_REFRESH:
		if (p->Handle)
		{
			p->SoftwareVolume = QueryAdvPlatform(ADVPLATFORM_SYSTEMVOLUME)==0;
			UpdateVolumeSoftLog(p);
			UpdatePCM(p,&p->InputFormat);
		}
		break;

	case NODE_HIBERNATE:
		if (Size == sizeof(int))
 			Result = Hibernate(p,*(int*)Data);
		break;

	case FLOW_TOTAL:
		if (Size == sizeof(int))
		{
			p->TotalBytes = *(const int*)Data * p->BytesPerSample;
			Result = ERR_NONE;
		}
		break;

	case FLOW_EMPTY:
		Reset(p);
		p->VolumeRamp = 0;
		Result = ERR_NONE;
		break;

	case TIMER_PLAY: SETVALUECMP(p->Play,bool_t,UpdatePlay(p),EqBool); break;
	case TIMER_TIME:
		if (Size == sizeof(tick_t))
		{
			EnterCriticalSection(&p->Section);
			p->Tick = *(tick_t*)Data;
			p->TimeRef = GetTimeTick();
			LeaveCriticalSection(&p->Section);
			Result = ERR_NONE;
		}
		break;

	case TIMER_SPEED:
		if (Size == sizeof(fraction))
		{
			Result = ERR_NONE;
			if (!EqFrac( &p->Speed, (const fraction*)Data ))
			{
				p->Speed = *(const fraction*)Data;
				Result = Update(p);
			}
		}
		break;
	}
	return Result;
}

static waveout WaveOut;

void WaveOut_Init()
{
	WAVEOUTCAPS Caps;
	waveout* p = &WaveOut;

	NodeFill(&p->VMT,sizeof(waveout),Enum,Get,Set);
	p->Volume = 70;
	p->VolumeSoftLog = 256;
	p->Quality = 2;
	p->BufferTime = TICKSPERSEC*5;
	p->Speed.Den = p->Speed.Num = 1;
	p->SpeedTime.Num = TICKSPERSEC;
	p->SpeedTime.Den = GetTimeFreq();
	p->PCM = NULL;
	waveOutGetDevCaps(WAVE_MAPPER,&Caps,sizeof(Caps));
	p->MonoVol = (Caps.dwSupport & WAVECAPS_LRVOLUME) == 0;
	p->SoftwareVolume = QueryAdvPlatform(ADVPLATFORM_SYSTEMVOLUME)==0;

	InitializeCriticalSection(&p->Section);
	if (waveOutGetNumDevs())
		NodeRegister(&p->VMT,PRI_DEFAULT);

	GetVolume(p);
	UpdateVolumeSoftLog(p);
}

void WaveOut_Done()
{
	waveout* p = &WaveOut;
	PCMRelease(p->PCM);
	DeleteCriticalSection(&p->Section);
	NodeUnRegister(&p->VMT);
}

#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -