summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/examples/ne566.cpp
blob: f238308c5019c539dbb6e610e7098745f49ea1ef (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// license:CC0-1.0
// copyright-holders:Couriersud

/*
 * ne566.cpp
 *
 */

//! [ne566_example]
#include "netlist/devices/net_lib.h"

// ./nltool -t 1 -l X.3 -l X.4 -n oscillator src/lib/netlist/examples/ne566.cpp
//  X.3 : Square out
//  X.4 : Triangle out

NETLIST_START(oscillator)
{

	SOLVER(Solver, 48000)

	ANALOG_INPUT(I_V12, 12.0)

	ANALOG_INPUT(I_VC, 11.9 - 0.2)

	NE566_DIP(X)

	RES(R1, 10000)  // ~20 Hz.
	CAP(C1, 1e-6)
	NET_C(I_V12, R1.1, X.8)
	NET_C(R1.2, X.6)
	NET_C(I_VC, X.5)
	NET_C(GND, X.1, C1.2)
	NET_C(C1.1, X.7)
}
//! [ne566_example]
.no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
// license:BSD-3-Clause
// copyright-holders:Sandro Ronco
/********************************************************************

    Support for VG-5000 .k7 cassette images

********************************************************************/

#include "vg5k_cas.h"

#include "multibyte.h"


#define SMPLO   -32768
#define SILENCE 0
#define SMPHI   32767


static int k7_size; // FIXME: global variable prevents multiple instances

/*******************************************************************
   Generate one high-low cycle of sample data
********************************************************************/
static inline int vg5k_cas_cycle(int16_t *buffer, int sample_pos, int len)
{
	int i = 0;

	if (buffer)
	{
		while( i < len)
		{
			buffer[ sample_pos + i ] = SMPHI;
			i++;
		}

		while( i < len * 2 )
		{
			buffer[ sample_pos + i ] = SMPLO;
			i++;
		}
	}
	return len * 2;
}


/*******************************************************************
   Generate n samples of silence
********************************************************************/
static inline int vg5k_cas_silence(int16_t *buffer, int sample_pos, int len)
{
	int i = 0;

	if ( buffer )
		for( i = 0; i < len; i++)
			buffer[ sample_pos + i ] = SILENCE;

	return len;
}


/*******************************************************************
   Generate the end-byte samples
********************************************************************/
static inline int vg5k_cas_eob(int16_t *buffer, int sample_pos)
{
	int i, samples = 0;

	for (i = 0; i < 4; i++)
		samples += vg5k_cas_cycle( buffer, sample_pos + samples, 5);

	samples += vg5k_cas_cycle( buffer, sample_pos + samples, 10);

	return samples;
}


static inline int vg5k_cas_byte(int16_t *buffer, int sample_pos, uint8_t data)
{
/* Writing an entire byte */
	int i, samples;

	samples = 0;
	for ( i = 0; i < 8; i++ )
	{
		if ( data & 0x01 )
		{
			samples += vg5k_cas_cycle( buffer, sample_pos + samples, 5 );
			samples += vg5k_cas_cycle( buffer, sample_pos + samples, 5 );
		}
		else
		{
			samples += vg5k_cas_cycle( buffer, sample_pos + samples, 10 );
		}

		data >>= 1;
	}
	return samples;
}


/*******************************************************************
   Generate n sample of synchro
********************************************************************/
static inline int vg5k_k7_synchro(int16_t *buffer, int sample_pos, int len)
{
	int i, samples = 0;

	for ( i = 0; i < len ; i++ )
			samples += vg5k_cas_cycle( buffer, sample_pos + samples, 5);

	samples += vg5k_cas_eob( buffer, sample_pos + samples);

	return samples;
}


static int vg5k_handle_tap(int16_t *buffer, const uint8_t *casdata)
{
	int data_pos, sample_count;

	data_pos = 0;
	sample_count = 0;

	/* file has to start with an head block */
	if (casdata[0] != 0xd3  || casdata[1] != 0xd3 || casdata[2] != 0xd3)
		return -1;

	/* on the entire file*/
	while( data_pos < k7_size )
	{
		uint16_t  block_size = 0;

		/* Identify type of block */
		if (casdata[data_pos] == 0xd3)
		{
			/* head block have fixed size of 32 byte */
			block_size = 0x20;

			/* 1 sec of silence before the head block */
			sample_count += vg5k_cas_silence(buffer, sample_count, 44100);

			/* head block starts with 30000 samples of synchro */
			sample_count += vg5k_k7_synchro( buffer, sample_count, 30000 );
		}
		else if (casdata[data_pos] == 0xd6)
		{
			/* data block size is defined in head block */
			block_size = get_u16le(&casdata[data_pos - 4]) +  20;

			/* 10000 samples of silence before the data block */
			sample_count += vg5k_cas_silence(buffer, sample_count, 10000);

			/* data block starts with 7200 samples of synchro */
			sample_count += vg5k_k7_synchro( buffer, sample_count, 7200);
		}
		else
		{
			/* tries to handle files that do not respect the size declared in the head block */
			while (data_pos < k7_size && casdata[data_pos] != 0xd3 && casdata[data_pos] != 0xd6)
				data_pos++;
		}

		/* Data samples */
		for ( ; block_size ; data_pos++, block_size-- )
		{
			/* Make sure there are enough bytes left */
			if (data_pos > k7_size)
				return -1;

			sample_count += vg5k_cas_byte( buffer, sample_count, casdata[data_pos] );

			/* generate the end-byte samples */
			sample_count += vg5k_cas_eob( buffer, sample_count);
		}
	}

	/* Finish with 10000 samples of silence */
	sample_count += vg5k_cas_silence(buffer, sample_count, 10000);

	return sample_count;
}


/*******************************************************************
   Generate samples for the tape image
********************************************************************/
static int vg5k_k7_fill_wave(int16_t *buffer, int sample_count, const uint8_t *bytes, int)
{
	return vg5k_handle_tap(buffer, bytes);
}


/*******************************************************************
   Calculate the number of samples needed for this tape image classical
********************************************************************/
static int vg5k_k7_to_wav_size(const uint8_t *casdata, int caslen)
{
	k7_size = caslen ;

	return vg5k_handle_tap( nullptr, casdata );
}


static const cassette_image::LegacyWaveFiller vg5k_legacy_fill_wave =
{
	vg5k_k7_fill_wave,                      /* fill_wave */
	-1,                                     /* chunk_size */
	0,                                      /* chunk_samples */
	vg5k_k7_to_wav_size,                    /* chunk_sample_calc */
	44100,                                  /* sample_frequency */
	0,                                      /* header_samples */
	0                                       /* trailer_samples */
};

static cassette_image::error vg5k_k7_identify(cassette_image *cassette, cassette_image::Options *opts)
{
	return cassette->legacy_identify(opts, &vg5k_legacy_fill_wave);
}


static cassette_image::error vg5k_k7_load(cassette_image *cassette)
{
	return cassette->legacy_construct(&vg5k_legacy_fill_wave);
}


static const cassette_image::Format vg5k_k7_format =
{
	"k7",
	vg5k_k7_identify,
	vg5k_k7_load,
	nullptr
};


CASSETTE_FORMATLIST_START(vg5k_cassette_formats)
	CASSETTE_FORMAT(vg5k_k7_format)
	CASSETTE_FORMAT(cassette_image::wavfile_format)
CASSETTE_FORMATLIST_END