File: TZXAudioGenerator.cpp

package info (click to toggle)
ares 134%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 34,680 kB
  • sloc: cpp: 338,717; ansic: 89,036; sh: 52; makefile: 27
file content (165 lines) | stat: -rw-r--r-- 4,393 bytes parent folder | download
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//#include "..\stdafx.h"
#include "TZXAudioGenerator.h"
#include <stdlib.h>
#include "TZXFile.h"
#include <stdio.h>
#include <memory.h>


#define SECONDS_PER_BLOCK_CHUNK 60
#define BLOCK_SIZE (TZX_AUDIO_DATARATE * SECONDS_PER_BLOCK_CHUNK)
#define AUDIO_BUFFER_LENGTH (BLOCK_SIZE * m_nAudioBlocks)
#define HI 115
#define LO -115

TZXAudioGenerator::TZXAudioGenerator()
{
	m_pAudioData = (char *)malloc(BLOCK_SIZE);
	m_nAudioDataLengthinSamples = 0;
	m_nAudioBlocks = 1;
	m_bAmp = false;
}

TZXAudioGenerator::~TZXAudioGenerator()
{
}

void TZXAudioGenerator::SetAmp(bool bAmp)
{
	m_bAmp = bAmp;
}

void TZXAudioGenerator::AddByte(char byte)
{
	if (m_nAudioDataLengthinSamples == AUDIO_BUFFER_LENGTH)
	{
		// Need to increas the size of the buffer
		ExtendAudioBuffer();
	}

	m_pAudioData[m_nAudioDataLengthinSamples] = byte;
	m_nAudioDataLengthinSamples++;
}

void TZXAudioGenerator::ExtendAudioBuffer()
{
	//printf("Debug: extending audio buffer to %d bytes\n", AUDIO_BUFFER_LENGTH);
	char *pNewBuffer = (char *)malloc((m_nAudioBlocks + 1)*BLOCK_SIZE);
	char *pOldBuffer = m_pAudioData;
	memcpy(pNewBuffer, pOldBuffer, m_nAudioDataLengthinSamples);
	m_pAudioData = pNewBuffer;
	m_nAudioBlocks++;
	free(pOldBuffer);
}

void TZXAudioGenerator::GeneratePulse(int lengthInTStates, bool toggleAmp)
{
	// Calculate the length of the pulse in terms of samples
	// Note this method is not completely accurate so may need some finessing for very high speed turbo loaders to work accurately...
    double cycle = (double)TZX_AUDIO_DATARATE / (double)TZX_TSTATES_PER_SECOND;
	int samples = ((unsigned int)(0.5 + (cycle*(double)lengthInTStates)));
	for (int i = 0; i < samples; i++)
	{
		if (m_bAmp) AddByte(HI); else AddByte(LO);
	}

	// Automatically toggle the state unless we are specifically told not to
	if (toggleAmp)
	{
		m_bAmp = !m_bAmp;
	}
}

void TZXAudioGenerator::ResetBuffer()
{
	free(m_pAudioData);
	m_pAudioData = (char *)malloc(BLOCK_SIZE);
	m_nAudioDataLengthinSamples = 0;
	m_nAudioBlocks = 1;
	m_bAmp = false;
}

int TZXAudioGenerator::GetCurrentLength()
{
	return m_nAudioDataLengthinSamples;
}

void TZXAudioGenerator::AddSilence(int nLengthInMS)
{
	int samplesToAdd = (nLengthInMS * TZX_AUDIO_DATARATE) / 1000;
	
	if (nLengthInMS > 1  && m_bAmp)
	{
		int nRemainder = nLengthInMS - 1;
		AddSilence(1);
		m_bAmp = false;
		AddSilence(nRemainder);
	}
	else {
		for (int i = 0; i < samplesToAdd; i++)
		{
			if (m_bAmp) AddByte(HI); else AddByte(LO);
		}
	}
}

char *TZXAudioGenerator::GetAudioBufferPtr()
{
	return m_pAudioData;
}

bool TZXAudioGenerator::SaveAsUncompressedWav(const char *szFilename)
{
	FILE *hFile = NULL;
	hFile = fopen(szFilename, "wb");
	if (hFile == NULL) return false;

    // We create an uncompressed wav and manually hack the header together according to the data at the website below
	// http://www.topherlee.com/software/pcm-tut-wavformat.html

	char *riff = (char *)"RIFF";
	if (fwrite(riff, 4, 1, hFile) != 1) { fclose(hFile); return false; }

	int fileLength = m_nAudioDataLengthinSamples + 44;
	if (fwrite(&fileLength, 4, 1, hFile) != 1) { fclose(hFile); return false; }

	char *wave = (char *)"WAVEfmt ";
	if (fwrite(wave, 8, 1, hFile) != 1) { fclose(hFile); return false; }

	int formatDataLength = 16;
	if (fwrite(&formatDataLength, 4, 1, hFile) != 1) { fclose(hFile); return false; }

	short formatType = 1; // PCM
	if (fwrite(&formatType, 2, 1, hFile) != 1) { fclose(hFile); return false; }

	short channels = 1;
	if (fwrite(&channels, 2, 1, hFile) != 1) { fclose(hFile); return false; }

	int sampleRate = TZX_AUDIO_DATARATE;
	if (fwrite(&sampleRate, 4, 1, hFile) != 1) { fclose(hFile); return false; }
	if (fwrite(&sampleRate, 4, 1, hFile) != 1) { fclose(hFile); return false; }

	short bytesPerSample = 1;
	if (fwrite(&bytesPerSample, 2, 1, hFile) != 1) { fclose(hFile); return false; }

	int bitsPerSample = 8;
	if (fwrite(&bitsPerSample, 2, 1, hFile) != 1) { fclose(hFile); return false; }

	char *data = (char *)"data";
	if (fwrite(data, 4, 1, hFile) != 1) { fclose(hFile); return false; }

	int dataSize = m_nAudioDataLengthinSamples;
	if (fwrite(&dataSize, 4, 1, hFile) != 1) { fclose(hFile); return false; }

	for (int i = 0; i < dataSize; i++)
	{
		int n = m_pAudioData[i];
		n = n + 128;
		unsigned char b = (unsigned char) n;

		if (fwrite(&b, 1, 1, hFile) != 1) { fclose(hFile); return false; }
	}
	
	fclose(hFile);
	return true;
}