<commit_before>//
//  6560.hpp
//  Clock Signal
//
//  Created by <NAME> on 05/06/2016.
//  Copyright © 2016 <NAME>. All rights reserved.
//

#ifndef _560_hpp
#define _560_hpp

#include "../../Outputs/CRT/CRT.hpp"
#include "../../Outputs/Speaker.hpp"

namespace MOS {

// audio state
class Speaker: public ::Outputs::Filter<Speaker> {
	public:
		Speaker();

		void set_volume(uint8_t volume);
		void set_control(int channel, uint8_t value);

		void get_samples(unsigned int number_of_samples, int16_t *target);
		void skip_samples(unsigned int number_of_samples);

	private:
		unsigned int counters_[4];
		unsigned int shift_registers_[4];
		uint8_t control_registers_[4];
		uint8_t volume_;
};

/*!
	The 6560 Video Interface Chip ('VIC') is a video and audio output chip; it therefore vends both a @c CRT and a @c Speaker.

	To run the VIC for a cycle, the caller should call @c get_address, make the requested bus access
	and call @c set_graphics_value with the result.

	@c set_register and @c get_register provide register access.
*/
template <class T> class MOS6560 {
	public:
		MOS6560() :
				crt_(new Outputs::CRT::CRT(65*4, 4, Outputs::CRT::NTSC60, 1)),
				speaker_(new Speaker),
				horizontal_counter_(0),
				vertical_counter_(0),
				cycles_since_speaker_update_(0),
				is_odd_frame_(false),
				is_odd_line_(false) {
			crt_->set_composite_sampling_function(
				"float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)"
				"{"
					"uint c = texture(texID, coordinate).r;"
					"float y = float(c >> 4) / 4.0;"
					"uint yC = c & 15u;"
					"float phaseOffset = 6.283185308 * float(yC) / 16.0;"

					"float chroma = cos(phase + phaseOffset);"
					"return mix(y, step(yC, 14) * chroma, amplitude);"
				"}");

			// default to NTSC
			set_output_mode(OutputMode::NTSC);
		}

		void set_clock_rate(double clock_rate) {
			speaker_->set_input_rate((float)(clock_rate / 4.0));
		}

		std::shared_ptr<Outputs::CRT::CRT> get_crt() { return crt_; }
		std::shared_ptr<Outputs::Speaker> get_speaker() { return speaker_; }

		enum OutputMode {
			PAL, NTSC
		};

		/*!
			Sets the output mode to either PAL or NTSC.
		*/
		void set_output_mode(OutputMode output_mode) {
			output_mode_ = output_mode;
			uint8_t luminances[16] = {		// range is 0–4
				0, 4, 1, 3, 2, 2, 1, 3,
				2, 1, 2, 1, 2, 3, 2, 3
			};
			uint8_t pal_chrominances[16] = {	// range is 0–15; 15 is a special case meaning "no chrominance"
				15, 15, 5, 13, 2, 10, 0, 8,
				6, 7, 5, 13, 2, 10, 0, 8,
			};
			uint8_t ntsc_chrominances[16] = {
				15, 15, 2, 10, 4, 12, 6, 14,
				0, 8, 2, 10, 4, 12, 6, 14,
			};
			uint8_t *chrominances;
			Outputs::CRT::DisplayType display_type;

			switch(output_mode) {
				case OutputMode::PAL:
					chrominances = pal_chrominances;
					display_type = Outputs::CRT::PAL50;
					timing_.cycles_per_line = 71;
					timing_.line_counter_increment_offset = 0;
					timing_.lines_per_progressive_field = 312;
					timing_.supports_interlacing = false;
				break;

				case OutputMode::NTSC:
					chrominances = ntsc_chrominances;
					display_type = Outputs::CRT::NTSC60;
					timing_.cycles_per_line = 65;
					timing_.line_counter_increment_offset = 65 - 33;	// TODO: this is a bit of a hack; separate vertical and horizontal counting
					timing_.lines_per_progressive_field = 261;
					timing_.supports_interlacing = true;
				break;
			}

			crt_->set_new_display_type((unsigned int)(timing_.cycles_per_line*4), display_type);
//			crt_->set_visible_area(Outputs::CRT::Rect(0.1f, 0.1f, 0.8f, 0.8f));<commit_msg>Added some consts, for a minor safety improvement.<commit_after>//
//  6560.hpp
//  Clock Signal
//
//  Created by <NAME> on 05/06/2016.
//  Copyright © 2016 <NAME>. All rights reserved.
//

#ifndef _560_hpp
#define _560_hpp

#include "../../Outputs/CRT/CRT.hpp"
#include "../../Outputs/Speaker.hpp"

namespace MOS {

// audio state
class Speaker: public ::Outputs::Filter<Speaker> {
	public:
		Speaker();

		void set_volume(uint8_t volume);
		void set_control(int channel, uint8_t value);

		void get_samples(unsigned int number_of_samples, int16_t *target);
		void skip_samples(unsigned int number_of_samples);

	private:
		unsigned int counters_[4];
		unsigned int shift_registers_[4];
		uint8_t control_registers_[4];
		uint8_t volume_;
};

/*!
	The 6560 Video Interface Chip ('VIC') is a video and audio output chip; it therefore vends both a @c CRT and a @c Speaker.

	To run the VIC for a cycle, the caller should call @c get_address, make the requested bus access
	and call @c set_graphics_value with the result.

	@c set_register and @c get_register provide register access.
*/
template <class T> class MOS6560 {
	public:
		MOS6560() :
				crt_(new Outputs::CRT::CRT(65*4, 4, Outputs::CRT::NTSC60, 1)),
				speaker_(new Speaker),
				horizontal_counter_(0),
				vertical_counter_(0),
				cycles_since_speaker_update_(0),
				is_odd_frame_(false),
				is_odd_line_(false) {
			crt_->set_composite_sampling_function(
				"float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)"
				"{"
					"uint c = texture(texID, coordinate).r;"
					"float y = float(c >> 4) / 4.0;"
					"uint yC = c & 15u;"
					"float phaseOffset = 6.283185308 * float(yC) / 16.0;"

					"float chroma = cos(phase + phaseOffset);"
					"return mix(y, step(yC, 14) * chroma, amplitude);"
				"}");

			// default to NTSC
			set_output_mode(OutputMode::NTSC);
		}

		void set_clock_rate(double clock_rate) {
			speaker_->set_input_rate((float)(clock_rate / 4.0));
		}

		std::shared_ptr<Outputs::CRT::CRT> get_crt() { return crt_; }
		std::shared_ptr<Outputs::Speaker> get_speaker() { return speaker_; }

		enum OutputMode {
			PAL, NTSC
		};

		/*!
			Sets the output mode to either PAL or NTSC.
		*/
		void set_output_mode(OutputMode output_mode) {
			output_mode_ = output_mode;
			const uint8_t luminances[16] = {		// range is 0–4
				0, 4, 1, 3, 2, 2, 1, 3,
				2, 1, 2, 1, 2, 3, 2, 3
			};
			const uint8_t pal_chrominances[16] = {	// range is 0–15; 15 is a special case meaning "no chrominance"
				15, 15, 5, 13, 2, 10, 0, 8,
				6, 7, 5, 13, 2, 10, 0, 8,
			};
			const uint8_t ntsc_chrominances[16] = {
				15, 15, 2, 10, 4, 12, 6, 14,
				0, 8, 2, 10, 4, 12, 6, 14,
			};
			const uint8_t *chrominances;
			Outputs::CRT::DisplayType display_type;

			switch(output_mode) {
				case OutputMode::PAL:
					chrominances = pal_chrominances;
					display_type = Outputs::CRT::PAL50;
					timing_.cycles_per_line = 71;
					timing_.line_counter_increment_offset = 0;
					timing_.lines_per_progressive_field = 312;
					timing_.supports_interlacing = false;
				break;

				case OutputMode::NTSC:
					chrominances = ntsc_chrominances;
					display_type = Outputs::CRT::NTSC60;
					timing_.cycles_per_line = 65;
					timing_.line_counter_increment_offset = 65 - 33;	// TODO: this is a bit of a hack; separate vertical and horizontal counting
					timing_.lines_per_progressive_field = 261;
					timing_.supports_interlacing = true;
				break;
			}

			crt_->set_new_display_type((unsigned int)(timing_.cycles_per_line*4), display_type);
//			crt_->set_visible_area(Outputs::CRT::Rect(0.1f, 0.1f, 0.8f, 0.8f));
{'fraction_non_alphanumeric': 0.1278538812785388, 'fraction_numerical': 0.051196900511969005, 'mean_word_length': 3.5430546825895664, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1324640', 'n_tokens_mistral': 3346, 'n_tokens_neox': 2611, 'n_words': 686}