Quick actions

cmd+k|ctrl+k

Navigation

Languages

vp

Snippet info

Language

Lua

Visibility

public

Author

rmd

Created

2025-01-31T04:38:54.987843Z

Updated

2025-01-31T04:42:05.560913Z

local args = {...}

local videos = {
	NotAdvert = {
		fps = 15;
		videoSettings = {
			CanvasSize = Vector2.new(90,50);
			TextSize = 2;
		};
		Audio = "https://cdn.glitch.global/65fb8114-6418-4a81-8479-5ab02dae65fb/not_advert.wav?v=1737416825383";
		Data = "https://raw.githubusercontent.com/typicaalusername/ascii_player/refs/heads/main/not_Advert.lua";
	};
	jack = {
		fps = 25;
		videoSettings = {
			CanvasSize = Vector2.new(300, 150);
			TextSize = 2;
		};
		Data = "https://raw.githubusercontent.com/typicaalusername/ascii_player/refs/heads/main/jack";
		Audio = "https://cdn.glitch.global/65fb8114-6418-4a81-8479-5ab02dae65fb/jackass.wav?v=1737420184031";
	};
	y2k = {
		fps = 7.5;
		videoSettings = {
			CanvasSize = Vector2.new(178, 100);
			TextSize = 2;
		};
		Data = "https://cdn.glitch.global/9fb0912f-974f-43b5-9ca3-d77c367f8342/Ronald%20McDonald%20insanity%20vid.wav?v=1738298184369";
		Audio = "https://cdn.glitch.global/61ed2cce-4ba4-44e5-953a-caba7cfd7f9f/Ronald%20McDonald%20insanity.wav?v=1738297170727";
	};
}
-- https://raw.githubusercontent.com/typicaalusername/ascii_player/refs/heads/main/y2k
local video = videos[args[1] or "y2k"]
local vidsettings = video.videoSettings

local multiplysize = 1

local part = nil; local label = nil local backlabel = nil do
	local Part = Instance.new("Part")
	Part.CFrame = (game:GetService("RunService"):IsStudio() and CFrame.new(15,15,5) or owner.Character.HumanoidRootPart.CFrame * CFrame.new(0,5+(.5*multiplysize),-5) * CFrame.Angles(0,math.rad(180),0))
	Part.BottomSurface = Enum.SurfaceType.Smooth
	Part.Transparency = 0.8
	Part.TopSurface = Enum.SurfaceType.Smooth
	Part.Color = Color3.fromRGB(159, 161, 172)
	Part.Material = Enum.Material.Glass
	Part.Size = Vector3.new(11.800000190734863, 6.849999904632568, 0.10000000149011612)*multiplysize
	Part.Anchored = true

	local SurfaceGui = Instance.new("SurfaceGui")
	SurfaceGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
	SurfaceGui.ClipsDescendants = true
	SurfaceGui.MaxDistance = 1000
	SurfaceGui.SizingMode = Enum.SurfaceGuiSizingMode.FixedSize
	SurfaceGui.CanvasSize = vidsettings.CanvasSize
	--SurfaceGui.PixelsPerStud = 8/multiplysize
	SurfaceGui.Brightness = 5
	SurfaceGui.Parent = Part

	local Frame = Instance.new("Frame")
	Frame.Size = UDim2.new(1, 0, 1, 0)
	Frame.BorderColor3 = Color3.fromRGB(0, 0, 0)
	Frame.BorderSizePixel = 0
	Frame.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
	Frame.Parent = SurfaceGui

	local TextLabel = Instance.new("TextLabel")
	TextLabel.Size = UDim2.new(1, 0, 1, 0)
	TextLabel.BorderColor3 = Color3.fromRGB(0, 0, 0)
	TextLabel.BackgroundTransparency = 1
	TextLabel.BorderSizePixel = 0
	TextLabel.TextStrokeTransparency = 0
	TextLabel.TextStrokeColor3 = Color3.fromRGB(115, 115, 115)
	TextLabel.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
	TextLabel.FontSize = Enum.FontSize.Size14
	TextLabel.TextSize = vidsettings.TextSize
	TextLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
	TextLabel.Text = " "
	TextLabel.TextWrapped = true
	TextLabel.Font = Enum.Font.Code
	TextLabel.Parent = Frame

	local back = Instance.new("SurfaceGui")
	back.Name = "back"
	back.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
	back.Face = Enum.NormalId.Back
	back.ClipsDescendants = true
	back.MaxDistance = 1000
	back.SizingMode = Enum.SurfaceGuiSizingMode.PixelsPerStud
	back.Parent = Part

	local TextLabel1 = Instance.new("TextLabel")
	TextLabel1.Size = UDim2.new(1, 0, 1, 0)
	TextLabel1.BorderColor3 = Color3.fromRGB(0, 0, 0)
	TextLabel1.BackgroundTransparency = 1
	TextLabel1.BorderSizePixel = 0
	TextLabel1.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
	TextLabel1.FontSize = Enum.FontSize.Size14
	TextLabel1.TextSize = 14
	TextLabel1.TextColor3 = Color3.fromRGB(255, 255, 255)
	TextLabel1.Text = "oh mah gah"
	TextLabel1.TextWrapped = true
	TextLabel1.TextWrap = true
	TextLabel1.Font = Enum.Font.Code
	TextLabel1.TextScaled = true
	TextLabel1.Parent = back
	backlabel = TextLabel1

	Part.Parent = script
	part = Part
	label = TextLabel
end

local framerate = video.fps
local asciidata = loadstring(game:GetService("HttpService"):GetAsync(video.Data))()
local frames = asciidata

local totalframes = #frames
local duration = totalframes / framerate

local waveparent = part

local timePosition = 0
do
	local runService = game:GetService("RunService")
	local conn = {}
	local data

	local windowSize = 512
	local baseComponentFrequency = 440
	local playbackSpeed = 1
	local volume = 1
	local bitCrush = 1
	local playing = false

	local byteOffset = 16
	local formatChunkSize, channels, samplingRate, bitsPerSample
	local header, dataSize, samples, maxValue

	local byteOffset = 16
	local formatChunkSize, channels, samplingRate, bitsPerSample
	local header, dataSize, samples, maxValue

	local waves = {}
	local function makeSine(i, frequency)
		local s = Instance.new("Sound")
		s.SoundId = "rbxassetid://9040512197"
		s.Volume = 0
		s.Playing = true
		s.Looped = true
		s.Parent = waveparent
		s.Name = i
		s.RollOffMaxDistance = 100

		local freqPbs = frequency / baseComponentFrequency

		if freqPbs > 20 then
			freqPbs = frequency / 1050
			s.SoundId = "rbxassetid://198099744"
		end
		s.PlaybackSpeed = freqPbs

		return s
	end

	for i = 0, windowSize / 2  do
		table.insert(waves, makeSine(i, 0))
	end

	local function getString(length, offset, blob)
		local str = ""

		for i = 0, length - 1 do
			str = str..string.char(buffer.readu8(blob, offset + i))
		end

		return str
	end

	local function fft(reals, imaginaries)
		local inLength = #reals

		for i = 0, inLength - 1 do
			local h = i
			local k = inLength
			local j = 0

			while true do
				k = bit32.rshift(k, 1)

				if k > 0 then
					j = bit32.bor(bit32.lshift(j, 1), bit32.band(h, 1))
					h = bit32.rshift(h, 1)
				else
					break
				end
			end

			if j > i then
				local temp = reals[j + 1]
				reals[j + 1] = reals[i + 1]
				reals[i + 1] = temp

				local temp = imaginaries[j + 1]
				imaginaries[j + 1] = imaginaries[i + 1]
				imaginaries[i + 1] = temp
			end
		end

		local n = 1

		while n * 2 <= inLength do
			local i = 0

			while i < inLength do
				local j = i

				while j < i + n do			
					local cos = math.cos(math.pi * (j - i) / n)
					local sin = math.sin(math.pi * (j - i) / n)
					local tre = reals[j + n + 1] * cos + imaginaries[j + n + 1] * sin
					local tim = -reals[j + n + 1] * sin + imaginaries[j + n + 1] * cos

					reals[j + n + 1] = reals[j + 1] - tre
					imaginaries[j + n + 1] = imaginaries[j + 1] - tim
					reals[j + 1] = reals[j + 1] + tre
					imaginaries[j + 1] = imaginaries[j + 1] + tim

					j = j + 1
				end

				i = i + n * 2
			end

			n = n * 2
		end
		return reals, imaginaries
	end

	function link(arg)
		playing = false
		timePosition = 0
		if data then
			buffer.fill(data, 0, 0, buffer.len(data))
		end
		data = buffer.fromstring(arg)

		byteOffset = 16
		formatChunkSize = buffer.readu32(data, byteOffset)
		byteOffset = 22
		channels = buffer.readu16(data, byteOffset)
		byteOffset = 24
		samplingRate = buffer.readu32(data, byteOffset)
		byteOffset = 34
		bitsPerSample = buffer.readu16(data, byteOffset)
		byteOffset = byteOffset + 2

		if formatChunkSize == 18 then
			byteOffset = byteOffset + 2
		elseif formatChunkSize == 40 then
			byteOffset = byteOffset + 24
		elseif formatChunkSize ~= 16 then
			error("Invalid wav file")
		elseif channels == 2 then
			error("File must be mono")
		end

		header = ""

		while header ~= "data" do
			header = getString(4, byteOffset, data)
			byteOffset = byteOffset + 1
		end

		byteOffset = byteOffset + 3

		dataSize = buffer.readu32(data, byteOffset)
		samples = dataSize / channels / (bitsPerSample / 8)
		maxValue = 2 ^ bitsPerSample

		for i, wave in next, waves do
			i = i - 1
			local frequency = i * samplingRate / windowSize * math.abs(playbackSpeed)
			local freqPbs = frequency / baseComponentFrequency

			if freqPbs > 20 then
				freqPbs = frequency / 1050
				wave.SoundId = "rbxassetid://198099744"
			else
				wave.SoundId = "rbxassetid://9040512197"
			end
			wave.PlaybackSpeed = freqPbs
		end
		playing = true
	end

	local deltaTime = 0
	local previousWaitTime = os.clock()
	local previousIndex = -1
	local reals = {}
	local imaginaries = {}

	function play(timepos)
		if playing then
			timePosition = (timePosition + deltaTime * playbackSpeed) % (samples / samplingRate)
			local index = math.floor(timePosition * (samplingRate / windowSize)) * windowSize

			local previousSample = 0
			for i = 1, windowSize do    
				local sample = 0

				if bitsPerSample == 8 then
					sample = buffer.readi8(data, byteOffset + index + (i - 1))
				elseif bitsPerSample == 16 then
					sample = buffer.readi16(data, byteOffset + index * 2 + (i - 1) * 2)
				elseif bitsPerSample == 32 then
					sample = buffer.readi32(data, byteOffset + index * 4 + (i - 1) * 4)
				end

				if i % (bitCrush or 1) == 0 or i == 1 then
					reals[i] = sample / maxValue
				else
					reals[i] = previousSample
				end

				previousSample = reals[i]
				imaginaries[i] = 0
			end

			reals, imaginaries = fft(reals, imaginaries)

			for i, wave in pairs(waves) do
				local real = reals[i]
				local imaginary = imaginaries[i]
				local magnitude = Vector2.new(real, imaginary).Magnitude
				local phase = math.atan2(imaginary, real)

				local pit = ((i - 1) * (samplingRate / windowSize)) * math.abs(playbackSpeed)
				local crossPoint = pit / baseComponentFrequency > 20 and 2.531 or 0.812
				local halfWavePeriod = pit / baseComponentFrequency > 20 and (1 / 1050 / 2) or (1 / baseComponentFrequency / 2)

				if not wave or wave.Parent ~= waveparent then
					wave:Destroy()
					waves[i] = makeSine(i - 1, pit)
					wave = waves[i]
				end

				wave.TimePosition = crossPoint + (phase / math.pi) * halfWavePeriod
				wave.Volume = magnitude * 0.01 * volume
			end

			previousIndex = index
		end

		deltaTime = os.clock() - previousWaitTime
		previousWaitTime = os.clock()

		return timePosition
	end
end

link(game:GetService("HttpService"):GetAsync(video.Audio))

function lzw_decompress(compressed_data)
	local dictionary = {}
	for i = 0, 255 do
		dictionary[i] = string.char(i)
	end
	local dict_size = 256
	local current_code = compressed_data[1]
	local current_string = dictionary[current_code]
	local decompressed_data = {current_string}
	for i = 2, #compressed_data do
		local code = compressed_data[i]
		local entry
		if dictionary[code] then
			entry = dictionary[code]
		elseif code == dict_size then
			entry = current_string .. string.sub(current_string, 1, 1)
		end
		table.insert(decompressed_data, entry)
		dictionary[dict_size] = current_string .. string.sub(entry, 1, 1)
		dict_size = dict_size + 1
		current_string = entry
	end

	return table.concat(decompressed_data)
end

local curframe = 1
local syncing = false
local t = os.clock()
local more = os.clock()
game:GetService("RunService").Heartbeat:Connect(function(dt)		
	local r1 = duration / totalframes
	local r2 = r1 * curframe

	backlabel.Text = `server fps: {math.round((1/dt)*100)/100}\nvideo fps: {framerate}\ntimepos desync: {math.round((timePosition - r2)*100)/100}{(syncing and "\nresyncing" or "")}`

	play()

	if os.clock()-t >= 1/framerate then
		t = os.clock()
		label.Text = lzw_decompress(frames[curframe])
		if #frames<curframe+1 then
			curframe = 1
			timePosition = 0
		else
			curframe+=1
		end
	end

	if os.clock()-more >= 1/144 then
		more = os.clock()
		if timePosition - r2 >= .2 then
			syncing = true
			timePosition = r2
			task.delay(.1,function()
				syncing = false
			end)
		end
	end
end)
INFO