Commits

Lars Viklund committed 9843980

Multichannel/standalone support

Comments (0)

Files changed (5)

 link_directories(${Boost_LIBRARY_DIRS})
 
 set(OSC_SOURCES
+"fallbacks.cc"
 "linalg.h"
 "osc_main.cc"
 "oscilloscope.cc"
 "oscilloscope.h"
-"resource.rc"
 "resource.h"
+"resource.rc"
 "view.h"
 )
 
+#include "zvfs_client.h"
+
+template <size_t N>
+vfs::Blob make_blob(unsigned char const (&arr)[N]) {
+	return{ (char const*)arr, (char const*)arr + N };
+}
+
+void register_fallback_resources()
+{
+	typedef unsigned char BYTE;
+#include "g_osc_vs_4_0.h"
+#include "g_osc_vs_4_0_9_3.h"
+#include "g_osc_ps_4_0.h"
+#include "g_osc_ps_4_0_9_3.h"
+
+#include "g_particle_vs_4_0.h"
+#include "g_particle_vs_4_0_9_3.h"
+#include "g_particle_ps_4_0.h"
+#include "g_particle_ps_4_0_9_3.h"
+
+#include "g_fpl_vs_4_0.h"
+#include "g_fpl_vs_4_0_9_3.h"
+#include "g_fpl_ps_4_0.h"
+#include "g_fpl_ps_4_0_9_3.h"
+
+#include "g_compose_line_vs.h"
+#include "g_compose_line_ps.h"
+	vfs::store_fallback_resource("/g_osc_vs_4_0.cso", make_blob(g_osc_vs_4_0), 0);
+	vfs::store_fallback_resource("/g_osc_vs_4_0_9_3.cso", make_blob(g_osc_vs_4_0_9_3), 0);
+	vfs::store_fallback_resource("/g_osc_ps_4_0.cso", make_blob(g_osc_ps_4_0), 0);
+	vfs::store_fallback_resource("/g_osc_ps_4_0_9_3.cso", make_blob(g_osc_ps_4_0_9_3), 0);
+	vfs::store_fallback_resource("/g_particle_vs_4_0.cso", make_blob(g_particle_vs_4_0), 0);
+	vfs::store_fallback_resource("/g_particle_vs_4_0_9_3.cso", make_blob(g_particle_vs_4_0_9_3), 0);
+	vfs::store_fallback_resource("/g_particle_ps_4_0.cso", make_blob(g_particle_ps_4_0), 0);
+	vfs::store_fallback_resource("/g_particle_ps_4_0_9_3.cso", make_blob(g_particle_ps_4_0_9_3), 0);
+	vfs::store_fallback_resource("/g_fpl_vs_4_0.cso", make_blob(g_fpl_vs_4_0), 0);
+	vfs::store_fallback_resource("/g_fpl_vs_4_0_9_3.cso", make_blob(g_fpl_vs_4_0_9_3), 0);
+	vfs::store_fallback_resource("/g_fpl_ps_4_0.cso", make_blob(g_fpl_ps_4_0), 0);
+	vfs::store_fallback_resource("/g_fpl_ps_4_0_9_3.cso", make_blob(g_fpl_ps_4_0_9_3), 0);
+	vfs::store_fallback_resource("/g_compose_line_vs.cso", make_blob(g_compose_line_vs), 0);
+	vfs::store_fallback_resource("/g_compose_line_ps.cso", make_blob(g_compose_line_ps), 0);
+}
 		_view->set_window(*this);
 		_spline_drawer = std::make_unique<SplineDrawer>(_view.get());
 		static_api_ptr_t<visualisation_manager>()->create_stream(_vis_stream, visualisation_manager::KStreamFlagNewFFT);
-		_vis_stream->set_channel_mode(visualisation_stream_v2::channel_mode_mono);
+		_vis_stream->set_channel_mode(
+			(_config.mixing == OscilloscopeConfig::Mixing::DOWNMIX)
+			? visualisation_stream_v2::channel_mode_mono
+			: visualisation_stream_v2::channel_mode_default);
 		_context_menu = make_context_menu();
 		_context_contexts = gather_menu_contexts((HMENU)*_context_menu);
 		auto check_menu_radio_item = [](MenuItemContext ctx) {
 				_config.mixing = toggle(_config.mixing);
 				ctx.h.CheckMenuItem(ctx.offset,
 									make_checking_flags(_config.mixing));
+				_vis_stream->set_channel_mode(
+					(_config.mixing == OscilloscopeConfig::Mixing::DOWNMIX)
+					? visualisation_stream_v2::channel_mode_mono
+					: visualisation_stream_v2::channel_mode_default);
 			};
 			_[ID_LOWQUALITYMODE] = [&] {
 				auto& ctx = this->_context_contexts[ID_LOWQUALITYMODE];
 			auto const W = (int)_config.duration / 1000.0f;
 			auto const zoom = (int)_config.zoom / 100.0f;
 			_vis_stream->get_chunk_absolute(chunk, t-W/2.0f, W);
-			_spline_drawer->update_spline(zoom, chunk.get_data(), chunk.get_sample_count());
-			_spline_drawer->update_extents((float)(t-W/2.0f), (float)(t+W/2.0f));
+			SplineDrawer::Data data = {};
+			data.num_channels = chunk.get_channel_count();
+			data.left_time = (float)(t - W / 2.0f);
+			data.right_time = (float)(t + W / 2.0f);
+			data.zoom = zoom;
+			data.samples = chunk.get_data();
+			data.num_frames = chunk.get_sample_count();
+			_spline_drawer->update_spline(data);
 			_spline_drawer->update();
 			_spline_drawer->draw();
 		}
 
 static mainmenu_commands_factory_t<VisMenu> g_vis_menu;
 
-DECLARE_COMPONENT_VERSION("Oscilloscope (D3D11.0)", "0.11", "zao")
+DECLARE_COMPONENT_VERSION("Oscilloscope (D3D11.0)", "0.12", "zao")
 VALIDATE_COMPONENT_FILENAME("foo_vis_osc_dx110.dll")
 int64_t Timer::elapsed() { return _last.QuadPart - _base.QuadPart; }
 int64_t Timer::frequency() const { return _frequency.QuadPart; }
 
+void register_fallback_resources();
 
-SplineDrawer::SplineDrawer(View* view) : _view(view), _num_vertices(0)
-#if SWEET_PARTICLES
-	, _num_particles(0)
-#endif
+SplineDrawer::SplineDrawer(View* view) : _view(view)
 {
 	_timer.update();
 	_last_resource_refresh = _timer.elapsed();
-	{
-		typedef unsigned char BYTE; 
-#include "g_osc_vs_4_0.h"
-#include "g_osc_vs_4_0_9_3.h"
-#include "g_osc_ps_4_0.h"
-#include "g_osc_ps_4_0_9_3.h"
-
-#include "g_particle_vs_4_0.h"
-#include "g_particle_vs_4_0_9_3.h"
-#include "g_particle_ps_4_0.h"
-#include "g_particle_ps_4_0_9_3.h"
-
-#include "g_fpl_vs_4_0.h"
-#include "g_fpl_vs_4_0_9_3.h"
-#include "g_fpl_ps_4_0.h"
-#include "g_fpl_ps_4_0_9_3.h"
-
-#include "g_compose_line_vs.h"
-#include "g_compose_line_ps.h"
-		vfs::store_fallback_resource("/g_osc_vs_4_0.cso", make_blob(g_osc_vs_4_0), 0);
-		vfs::store_fallback_resource("/g_osc_vs_4_0_9_3.cso", make_blob(g_osc_vs_4_0_9_3), 0);
-		vfs::store_fallback_resource("/g_osc_ps_4_0.cso", make_blob(g_osc_ps_4_0), 0);
-		vfs::store_fallback_resource("/g_osc_ps_4_0_9_3.cso", make_blob(g_osc_ps_4_0_9_3), 0);
-		vfs::store_fallback_resource("/g_particle_vs_4_0.cso", make_blob(g_particle_vs_4_0), 0);
-		vfs::store_fallback_resource("/g_particle_vs_4_0_9_3.cso", make_blob(g_particle_vs_4_0_9_3), 0);
-		vfs::store_fallback_resource("/g_particle_ps_4_0.cso", make_blob(g_particle_ps_4_0), 0);
-		vfs::store_fallback_resource("/g_particle_ps_4_0_9_3.cso", make_blob(g_particle_ps_4_0_9_3), 0);
-		vfs::store_fallback_resource("/g_fpl_vs_4_0.cso", make_blob(g_fpl_vs_4_0), 0);
-		vfs::store_fallback_resource("/g_fpl_vs_4_0_9_3.cso", make_blob(g_fpl_vs_4_0_9_3), 0);
-		vfs::store_fallback_resource("/g_fpl_ps_4_0.cso", make_blob(g_fpl_ps_4_0), 0);
-		vfs::store_fallback_resource("/g_fpl_ps_4_0_9_3.cso", make_blob(g_fpl_ps_4_0_9_3), 0);
-		vfs::store_fallback_resource("/g_compose_line_vs.cso", make_blob(g_compose_line_vs), 0);
-		vfs::store_fallback_resource("/g_compose_line_ps.cso", make_blob(g_compose_line_ps), 0);
-	}
+	register_fallback_resources();
 	load_fixed_assets();
 	load_refreshable_assets();
 }
 	auto level = _view->feature_level;
 	bool downlevel = level < D3D_FEATURE_LEVEL_10_0;
 	{
-		if (downlevel) {
-			_line_vs_resource.set_if_empty("/g_osc_vs_4_0_9_3.cso");
-			_line_ps_resource.set_if_empty("/g_osc_ps_4_0_9_3.cso");
-		}
-		else {
-			_line_vs_resource.set_if_empty("/g_osc_vs_4_0.cso");
-			_line_ps_resource.set_if_empty("/g_osc_ps_4_0.cso");
-		}
-
-		_line_vs_resource.refresh();
-		_line_ps_resource.refresh();
-		if (_line_vs_resource.is_new() || _line_ps_resource.is_new()) {
-			auto vs_bytecode = _line_vs_resource.contents();
-			auto ps_bytecode = _line_ps_resource.contents();
-			
-			std::vector<D3D11_INPUT_ELEMENT_DESC> ieds = {
-				{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }
-			};
-			_line_stuff = make_stuff(_view->device,
-									 vs_bytecode,
-									 ps_bytecode,
-									 ieds,
-									 D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP);
-		}
-	}
-	{
 		_line_compose_vs_resource.set_if_empty("/g_compose_line_vs.cso");
 		_line_compose_ps_resource.set_if_empty("/g_compose_line_ps.cso");
 
 									num_existing_elements);
 		}
 	}
-#if SWEET_PARTICLES
-	{
-		std::unique_ptr<vfs::Blob> vs_bytecode, ps_bytecode;
-		if (level >= D3D_FEATURE_LEVEL_10_0) {
-			vs_bytecode = vfs::get_resource_contents("/g_particle_vs_4_0.cso");
-			ps_bytecode = vfs::get_resource_contents("/g_particle_ps_4_0.cso");
-		} else {
-			vs_bytecode = vfs::get_resource_contents("/g_particle_vs_4_0_9_3.cso");
-			ps_bytecode = vfs::get_resource_contents("/g_particle_ps_4_0_9_3.cso");
-		}
-
-		_particle_stuff = Stuff();
-		hr = _view->device->CreateVertexShader(
-			vs_bytecode->data(), vs_bytecode->size(), nullptr, &_particle_stuff.vertex_shader);
-		hr = _view->device->CreatePixelShader(
-			ps_bytecode->data(), ps_bytecode->size(), nullptr, &_particle_stuff.pixel_shader);
-
-		std::vector<D3D11_INPUT_ELEMENT_DESC> ieds = {
-			{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0,  D3D11_INPUT_PER_VERTEX_DATA, 0 },
-			{ "VELOCITY", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8,  D3D11_INPUT_PER_VERTEX_DATA, 0 },
-			{ "AGE",      0, DXGI_FORMAT_R32_FLOAT,    0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0 },
-			{ "LIFESPAN", 0, DXGI_FORMAT_R32_FLOAT,    0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0 }
-		};
-		hr = _view->device->CreateInputLayout(ieds.data(),
-												ieds.size(),
-												vs_bytecode->data(),
-												vs_bytecode->size(),
-												&_particle_stuff.input_layout);
-		_particle_stuff.primitive_topology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
-	}
-#endif
 }
 
-void SplineDrawer::update_extents(float left_time, float right_time) {
-	float const INCREMENT = 1.0f;
-	std::vector<float> time_lines;
-	auto L = std::floor(left_time / INCREMENT);
-	auto R = std::ceil(right_time / INCREMENT);
-	for (float t = L; t <= R; ++t) {
-		auto t_x = 2.0f * ((t * INCREMENT) - left_time) / (right_time - left_time) - 1.0f;
-		time_lines.push_back(t_x);
-	}
-
-	auto target = _view->target();
-	Float2 window_extents{(float)target._w, (float)target._h};
-		
-	auto ndc_to_window = [&](Float2 ndc) {
-		return (ndc + 1.0f)/2.0f * window_extents;
-	};
-}
-
-void SplineDrawer::update_spline(float zoom, float const* points, size_t num_elements) {
+void SplineDrawer::update_spline(Data data) {
 	HRESULT hr = S_OK;
-	int n = num_elements;
+	int n = data.num_frames;
 	std::vector<Vertex> vs;
 	vs.reserve(n);
-	for (int i = 0; i < n; ++i) {
-		float x = 2.0f*i/(n-1) - 1.0f;
-		Vertex v = { x, zoom * points[i] };
-		vs.emplace_back(std::move(v));
+	auto channel_offset = [&](int ch) {
+		auto k0 = (float)ch     / data.num_channels;
+		auto k1 = (float)(ch+1) / data.num_channels;
+		auto lerp = [](float a, float b, float k) {
+			return a*(1.0f - k) + b*k;
+		};
+		return lerp(1.0f, -1.0f, (k0 + k1) / 2);
+	};
+	float scale = data.zoom / data.num_channels;
+	for (int ch = 0; ch < data.num_channels; ++ch) {
+		for (int i = 0; i < n; ++i) {
+			float x = 2.0f*i / (n - 1) - 1.0f;
+			Vertex v = { x, channel_offset(ch) + scale * data.samples[i*data.num_channels + ch] };
+			vs.emplace_back(std::move(v));
+		}
 	}
-	create_or_update_buffer(_view->device, _view->context, vs, _vertices, _num_vertices);
 
 	auto target = _view->target();
 	Float2 window_extents{(float)target._w, (float)target._h};
 	float w = 3.0f;
 	float r = 1.0f;
 	std::vector<FPLInstance> instances;
-	if (num_elements > 0) {
-		int num_lines = n-1;
-		instances.reserve(num_lines);
-		for (int i = 0; i < num_lines; ++i) {
-			// http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter22.html
-			FPLInstance instance;
-			auto x0 = vs[i].x, y0 = vs[i].y;
-			auto x1 = vs[i + 1].x, y1 = vs[i + 1].y;
-			Float2 p0 = instance.from = ndc_to_window(Float2{x0, y0});
-			Float2 p1 = instance.to = ndc_to_window(Float2{x1, y1});
-			instance.width = w;
-			instance.r = r;
-			instances.emplace_back(std::move(instance));
+	if (n > 0) {
+		auto I = vs.data();
+		instances.reserve((n - 1)*data.num_channels);
+		for (int ch = 0; ch < data.num_channels; ++ch) {
+			int num_lines = n-1;
+			for (int i = 0; i < num_lines; ++i) {
+				// http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter22.html
+				FPLInstance instance;
+				auto x0 = I[0].x, y0 = I[0].y;
+				auto x1 = I[1].x, y1 = I[1].y;
+				Float2 p0 = instance.from = ndc_to_window(Float2{ x0, y0 });
+				Float2 p1 = instance.to = ndc_to_window(Float2{ x1, y1 });
+				instance.width = w;
+				instance.r = r;
+				instances.emplace_back(std::move(instance));
+				++I;
+			}
+			++I;
 		}
 	}
 	if (0) // debug line
 		instance.r = r;
 		instances.emplace_back(std::move(instance));
 	}
-#if 0
-	for (float f = 1.0f; f <= 1.0f; f += 2.0f) {
-		FPLInstance instance;
-		Float2 p0 = ndc_to_window({ -0.8f, -0.0f*f });
-		Float2 p1 = ndc_to_window({  0.8f,  0.0f*f });
-		instance.from = p0;
-		instance.to   = p1;
-		float w = 15.0f;
-		instance.width = w;
-		instance.r = r;
-		instances.emplace_back(std::move(instance));
-	}
-#endif
 	create_or_update_buffer(_view->device, _view->context, instances, _fpl_instances, _num_fpl_instances);
-#if SWEET_PARTICLES
-	for (int i = 0; i < 1000; ++i) {
-		static std::mt19937 rng;
-		std::uniform_real<float> x_dist(-1.2f, 1.2f);
-		std::uniform_real<float> y_dist(-1.2f, 1.2f);
-		std::uniform_real<float> angle(-0.4f, 0.4f);
-		Particle p;
-		p.x = x_dist(rng);
-		p.y = y_dist(rng);
-		float a = angle(rng);
-		float v = -0.1f;
-		p.vx = cos(a) * v;
-		p.vy = sin(a) * v;
-		p.age = 0.0f;
-		p.lifespan = 1.0f;
-		_particles.front().push_back(std::move(p));
-	}
-#endif
-}
 
-void SplineDrawer::update_spline(float zoom, std::vector<float> points) {
-	_timer.update();
-	double t = _timer.elapsed()/(double)_timer.frequency();
-	update_spline(zoom, points.data(), points.size());
+	// update extents
+	float const INCREMENT = 1.0f;
+	std::vector<float> time_lines;
+	auto L = std::floor(data.left_time / INCREMENT);
+	auto R = std::ceil(data.right_time / INCREMENT);
+	for (float t = L; t <= R; ++t) {
+		auto biased = ((t * INCREMENT) - data.left_time) / (data.right_time - data.left_time);
+		auto t_x = 2.0f * biased - 1.0f;
+		time_lines.push_back(t_x);
+	}
 }
 
 void SplineDrawer::update() {
 
 void SplineDrawer::draw() {
 	auto& ctx = _view->context;
-	if (0 && _vertices) {
-		apply_stuff(ctx, _line_stuff);
-		UINT stride = sizeof(Vertex), offset = 0;
-		ctx->IASetVertexBuffers(0, 1, &_vertices.p, &stride, &offset);
-		ctx->Draw(_num_vertices, 0);
-	}
 	if (_fpl_instances) {
 		apply_stuff(ctx, _fpl_stuff);
 
 
 void edge_equations_for_fat_line(float width, Float2 p0, Float2 p1, Float3* edges);
 
-template <size_t N>
-vfs::Blob make_blob(BYTE const (&arr)[N]) {
-	return {(char const*)arr, (char const*)arr + N};
-}
-
 template <typename T>
 static void create_or_update_buffer(CComPtr<ID3D11Device> device,
 									CComPtr<ID3D11DeviceContext> ctx,
 	void load_fixed_assets();
 	void load_refreshable_assets();
 
-	void update_extents(float left_time, float right_time);
-	void update_spline(float zoom, float const* points, size_t num_elements);
-	void update_spline(float zoom, std::vector<float> points);
+	struct Data {
+		int num_channels;
+		float zoom;
+		float left_time, right_time;
+		float const* samples;
+		size_t num_frames;
+	};
+
+	void update_spline(Data data);
 	void update();
 
 	void apply_stuff(CComPtr<ID3D11DeviceContext>& ctx, Stuff& stuff);
 	
 	int64_t _last_update;
 	int64_t _last_resource_refresh;
-	
-	RefreshableResource _line_vs_resource, _line_ps_resource;
-	CComPtr<ID3D11Buffer> _vertices;
-	int _num_vertices = 0;
-	Stuff _line_stuff;
-	vfs::Timestamp _line_vs_timestamp = -1, _line_ps_timestamp = -1;
-	
+
 	RefreshableResource _fpl_vs_resource, _fpl_ps_resource;
 	CComPtr<ID3D11Buffer> _window_extents_cb;
 	CComPtr<ID3D11Buffer> _fpl_vertex_ids;