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;
}
|