|
|
|||||||
| Home | Register | Downloads | FAQ | Members List | Calendar | Arcade | Mark Forums Read |
» Less advertising throughout
» Post and participate in discussions
» Network with other forum members
» Free private messaging
![]() |
|
|
Thread Tools | Display Modes |
|
|
#81 |
|
Registered User
Join Date: Mar 2011
Location: Missouri
Posts: 4
|
@refraction Okay. I see it know. The instructions starting with byte 08. But these would only rotate by multiples of 90 degrees (0 or 360, 90, 180, and 270.)
__________________
|
|
|
|
| Advertisement | [Remove Advertisement] | ||
|
|
|
#82 |
|
Registered User
![]() ![]() Join Date: Sep 2011
Location: Australia, Tasmania
Posts: 180
|
And the flip instructions don't rotate at all either...only flip in horizontal or vertical directions...
|
|
|
|
|
|
#83 |
|
Sober coder
![]() ![]() ![]() Join Date: Aug 2010
Location: London, UK
Posts: 433
|
Ok, here we go: spec v1.0 is out. Why 1.0? Because I feel Chip16 has reached a stage where it can be used for non-trivial things now. See OP for full spec. New instructions: Code:
0D 0X LL HH SNP Rx, HHLL Play Sound for HHLL miliseconds at the tone specified in address pointed to by Register X (uses current sound generator settings; ADSR, etc.).
0E AD SR VT SNG AD, VTSR Sound generator (applies to all sound tones which follow).
A = attack (0..15)
D = decay (0..15)
S = sustain (0..15, volume)
R = release (0..15)
V = volume (0..15)
T = type of sound:
00 = triangle wave
01 = sawtooth wave
02 = pulse wave (is just square for now)
03 = noise
non-valid values default to 0 output
D0 00 LL HH PAL HHLL Load the palette starting at address HHLL, 16*3 bytes, RGB format; used for all drawing since last vblank.
D1 0x 00 00 PAL Rx Load the palette starting at the address pointed to by Register X, 16*3 bytes, RGB format; used for all drawing since last vblank.
__________________
|
|
|
|
|
|
#84 |
|
Registered User
![]() ![]() Join Date: Sep 2011
Location: Australia, Tasmania
Posts: 180
|
Ok, since the updated spec is now out, here is my source code for the sound generation. It can most likely be optimized, but it should be simple enough to convert over to other languages ![]() How to use: Code:
uses
// sound generation unit
unit_SID
// WAV file format creator
unit_wavebuffer,
;
{...}
const
cDuration = 310; //ms
cFrequency = 100; //Hz
var
SID : TSID_Chip16;
outstream: TMemoryStream;
waveform : Integer;
begin
SID := TSID_Chip16.Create;
outstream := TMemoryStream.Create;
try
SID.Reset;
SID.SetSampleRate(44100);
SID.SetAttack(unit_SID.cAttack_2mSec);
SID.SetDecay(unit_SID.cDecay_6mSec);
SID.SetSustain(15);
SID.SetRelease(unit_SID.cRelease_300mSec);
// output all 4 wave types as an example
for waveform := 0 to 3 do
begin
SID.SetWaveform(waveform);
SID.GenerateWaveform(cFrequency,cDuration,outstream);
// save sound stream to file (would play instead in an emulator)
outstream.SaveToFile('SID_'+IntToStr(waveform)+'.wav');
end;
finally
SID.Free;
outstream.Free;
end;
Code:
unit unit_SID;
interface
uses
Classes;
const
cTriangleWave = $00;
cSawtoothWave = $01;
cPulseWave = $02;
cNoiseWave = $03;
cAttack_2mSec = 0;
cAttack_8mSec = 1;
cAttack_16mSec = 2;
cAttack_24mSec = 3;
cAttack_38mSec = 4;
cAttack_56mSec = 5;
cAttack_68mSec = 6;
cAttack_80mSec = 7;
cAttack_100mSec = 8;
cAttack_250mSec = 9;
cAttack_500mSec = 10;
cAttack_800mSec = 11;
cAttack_1Sec = 12;
cAttack_3Sec = 13;
cAttack_5Sec = 14;
cAttack_8Sec = 15;
cAttackDelayLUT : Array[0..15] Of LongWord =
// miliseconds
(
2,
8,
16,
24,
38,
56,
68,
80,
100,
250,
500,
800,
1000,
3000,
5000,
8000
);
{..............................................................................}
cDecay_6mSec = 0;
cDecay_14mSec = 1;
cDecay_48mSec = 2;
cDecay_72mSec = 3;
cDecay_114mSec = 4;
cDecay_168mSec = 5;
cDecay_204mSec = 6;
cDecay_240mSec = 7;
cDecay_300mSec = 8;
cDecay_750mSec = 9;
cDecay_1500mSec = 10;
cDecay_2400mSec = 11;
cDecay_3Sec = 12;
cDecay_9Sec = 13;
cDecay_15Sec = 14;
cDecay_24Sec = 15;
cDecayDelayLUT : Array[0..15] Of LongWord =
// miliseconds
(
6,
24,
48,
72,
114,
168,
204,
240,
300,
750,
1500,
2400,
3000,
9000,
15000,
24000
);
{..............................................................................}
cRelease_6mSec = 0;
cRelease_14mSec = 1;
cRelease_48mSec = 2;
cRelease_72mSec = 3;
cRelease_114mSec = 4;
cRelease_168mSec = 5;
cRelease_204mSec = 6;
cRelease_240mSec = 7;
cRelease_300mSec = 8;
cRelease_750mSec = 9;
cRelease_1500mSec = 10;
cRelease_2400mSec = 11;
cRelease_3Sec = 12;
cRelease_9Sec = 13;
cRelease_15Sec = 14;
cRelease_24Sec = 15;
cReleaseDelayLUT : Array[0..15] Of LongWord =
// miliseconds
(
6,
24,
48,
72,
114,
168,
204,
240,
300,
750,
1500,
2400,
3000,
9000,
15000,
24000
);
type
TADSRMode = (
adsrAttack,
adsrDecay,
adsrSustain,
adsrRelease,
adsrIdle
);
TReg4 = LongWord;
TReg8 = LongWord;
TReg12 = LongWord;
TReg16 = LongWord;
TReg24 = LongWord;
TSID_Chip16 = class
private
FAccumulator : TReg24;
FShiftRegister : TReg24;
// Fout = (Fn*Fclk/16777216)Hz
FFreq : TReg16;
// The waveform type; used for output function table lookup.
FWaveform : TReg8;
// 12-Bit pulse width (2048 = square wave)
// PWout = (PWn/40.95)%
FPulseWidth : TReg12;
FSampleRateHz : LongWord;
// sample rate time in seconds
FSampleRateS : Single;
// current ADSR mode
FADSRMode : TADSRMode;
// various ADSR counts and values for altering the volume
FAttackSampleCount : LongInt;
FDecaySampleCount : LongInt;
FReleaseSampleCount : LongInt;
FAttackCount : LongInt;
FAttackIncrement : LongInt;
FDecayCount : LongInt;
FDecayIncrement : LongInt;
FReleaseCount : LongInt;
FReleaseIncrement : LongInt;
FAttackDelay : TReg4;
FDecayDelay : TReg4;
FSustainVolume : TReg4;
FReleaseDelay : TReg4;
function GetOutputTriangle: TReg12;
function GetOutputSawtooth: TReg12;
function GetOutputPulse : TReg12;
function GetOutputNoise : TReg12;
procedure CalculateDelays;
procedure Gate;
procedure Release;
procedure UpdateADSR;
function GetADSRAmplitude: Single;
public
constructor Create;
procedure Reset;
procedure SetSampleRate(samplerate: LongWord);
procedure SetFrequency (frequency: TReg16);
procedure SetWaveform (waveform : TReg4);
procedure SetAttack (attack : TReg4);
procedure SetDecay (decay : TReg4);
procedure SetSustain (sustain : TReg4);
procedure SetRelease (release : TReg4);
procedure Clock;
function GetOutput: TReg12;
procedure GenerateWaveform(frequency,duration: TReg16; WAVFile: TStream);
property Waveform: TReg8 read FWaveform;
end;
implementation
uses
unit_wavbuffer;
constructor TSID_Chip16.Create;
begin
inherited Create;
SetSampleRate(44100);
Reset;
end;
procedure TSID_Chip16.Reset;
begin
FAccumulator := 0;
FShiftRegister := $7ffff8;
FFreq := 0;
FPulseWidth := 2048; // defaults to square wave
FAttackDelay := 0;
FDecayDelay := 0;
FSustainVolume := 0;
FReleaseDelay := 0;
CalculateDelays;
end;
procedure TSID_Chip16.CalculateDelays;
var
v1,v2 : Byte;
begin
v1 := 0;
v2 := 15;
FAttackSampleCount := (cAttackDelayLUT[FAttackDelay] * FSampleRateHz) div 1000;
FAttackIncrement := Trunc(65536 * (v2 - v1) / FAttackSampleCount);
v1 := 15;
v2 := FSustainVolume;
FDecaySampleCount := (cDecayDelayLUT[FDecayDelay] * FSampleRateHz) div 1000;
FDecayIncrement := Trunc(65536 * (v2 - v1) / FDecaySampleCount);
v1 := FSustainVolume;
v2 := 0;
FReleaseSampleCount := (cReleaseDelayLUT[FReleaseDelay] * FSampleRateHz) div 1000;
FReleaseIncrement := Trunc(65536 * (v2 - v1) / FReleaseSampleCount);
end;
function TSID_Chip16.GetADSRAmplitude: Single;
begin
case FADSRMode Of
adsrAttack : Result := (FAttackCount Shr 16) / 15;
adsrDecay : Result := (FDecayCount Shr 16) / 15;
adsrSustain : Result := FSustainVolume / 15;
adsrRelease : Result := (FReleaseCount Shr 16) / 15;
adsrIdle : Result := 0;
end;
end;
procedure TSID_Chip16.SetSampleRate(samplerate: LongWord);
begin
FSampleRateHz := samplerate;
FSampleRateS := 1/FSampleRateHz;
end;
procedure TSID_Chip16.SetFrequency(frequency: TReg16);
// scale frequency to the required SID internal frequency
//Fn = Fout / 0.0609
begin
FFreq := Trunc((frequency and $ffff) / 0.0609) and $ffff;
end;
procedure TSID_Chip16.SetWaveform(waveform: TReg4);
begin
FWaveform := waveform and $03;
end;
procedure TSID_Chip16.SetAttack(attack: TReg4);
begin
FAttackDelay := attack and $0f;
CalculateDelays;
end;
procedure TSID_Chip16.SetDecay(decay: TReg4);
begin
FDecayDelay := decay and $0f;
CalculateDelays;
end;
procedure TSID_Chip16.SetSustain(sustain: TReg4);
begin
FSustainVolume := sustain and $0f;
CalculateDelays;
end;
procedure TSID_Chip16.SetRelease(release: TReg4);
begin
FReleaseDelay := release and $0f;
CalculateDelays;
end;
// ----------------------------------------------------------------------------
// Clock 1 cycle.
// ----------------------------------------------------------------------------
procedure TSID_Chip16.Clock;
var
AccumulatorPrev: TReg24;
bit0 : TReg24;
begin
AccumulatorPrev := FAccumulator;
// Calculate new accumulator value (wrapping around due to 24-bit length);
FAccumulator := (FAccumulator + FFreq) and $ffffff;
// Shift noise register once for each time accumulator bit 19 is set high.
if ((AccumulatorPrev and $080000) = 0) and ((FAccumulator and $080000) <> 0) then
begin
bit0 := ((FShiftRegister shr 22) xor (FShiftRegister shr 17)) and $1;
FShiftRegister := FShiftRegister shl 1;
FShiftRegister := FShiftRegister and $7fffff;
FShiftRegister := FShiftRegister or bit0;
end;
end;
// Triangle:
// The upper 12 bits of the accumulator are used.
// The MSB is used to create the falling edge of the triangle by inverting
// the lower 11 bits. The MSB is thrown away and the lower 11 bits are
// left-shifted (half the resolution, full amplitude).
//
function TSID_Chip16.GetOutputTriangle: TReg12;
var
msb: TReg24;
begin
msb := FAccumulator and $800000;
if msb = 0 then
Result := not (FAccumulator shr 11) and $fff
else
Result := (FAccumulator shr 11) and $fff;
end;
// Sawtooth:
// The output is identical to the upper 12 bits of the accumulator.
//
function TSID_Chip16.GetOutputSawtooth: TReg12;
begin
Result := (FAccumulator shr 12) and $fff;
end;
// Pulse:
// The upper 12 bits of the accumulator are used.
// These bits are compared to the pulse width register by a 12 bit digital
// comparator; output is either all one or all zero bits.
//
function TSID_Chip16.GetOutputPulse: TReg12;
begin
Result := $000;
if (FAccumulator shr 12) >= FPulseWIdth then
Result := $fff;
end;
// Noise:
// The noise output is taken from intermediate bits of a 23-bit shift register
// which is clocked by bit 19 of the accumulator.
//
// Operation: Calculate EOR result, shift register, set bit 0 = result.
//
// ----------------------->---------------------
// | |
// ----EOR---- |
// | | |
// 2 2 2 1 1 1 1 1 1 1 1 1 1 |
// Register bits: 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 <---
// | | | | | | | |
// OSC3 bits : 7 6 5 4 3 2 1 0
//
// Since waveform output is 12 bits the output is left-shifted 4 times.
//
function TSID_Chip16.GetOutputNoise: TReg12;
begin
Result :=
((FShiftRegister and $400000) shr 11) or
((FShiftRegister and $100000) shr 10) or
((FShiftRegister and $010000) shr 7) or
((FShiftRegister and $002000) shr 5) or
((FShiftRegister and $000800) shr 4) or
((FShiftRegister and $000080) shr 1) or
((FShiftRegister and $000010) shl 1) or
((FShiftRegister and $000004) shl 2);
end;
function TSID_Chip16.GetOutput: TReg12;
begin
case FWaveform of
$00 : Result := GetOutputTriangle;
$01 : Result := GetOutputSawtooth;
$02 : Result := GetOutputPulse;
$03 : Result := GetOutputNoise;
else
Result := $000; // illegal waveform, so no output
end;
end;
procedure TSID_Chip16.Gate;
// start ADSR attack section
begin
FADSRMode := adsrAttack;
FAttackCount := 0;
FAttackSampleCount := (cAttackDelayLUT[FAttackDelay] * FSampleRateHz) div 1000;
end;
procedure TSID_Chip16.Release;
// start ADSR release section
begin
if FADSRMode <> adsrSustain then Exit;
FADSRMode := adsrRelease;
FReleaseCount := FSustainVolume * 65536;
FReleaseSampleCount := (cReleaseDelayLUT[FReleaseDelay] * FSampleRateHz) div 1000;
end;
procedure TSID_Chip16.UpdateADSR;
begin
case FADSRMode of
adsrAttack : begin
Inc(FAttackCount,FAttackIncrement);
Dec(FAttackSampleCount);
if FAttackSampleCount <= 0 then
begin
FADSRMode := adsrDecay;
FDecayCount := 15 * 65536;
FDecaySampleCount := (cDecayDelayLUT[FDecayDelay] * FSampleRateHz) div 1000;
end;
end;
adsrDecay : begin
Inc(FDecayCount,FDecayIncrement);
Dec(FDecaySampleCount);
if FDecaySampleCount <= 0 then
FADSRMode := adsrSustain;
end;
adsrRelease : begin
Inc(FReleaseCount,FReleaseIncrement);
Dec(FReleaseSampleCount);
if FReleaseSampleCount <= 0 then
FADSRMode := adsrIdle;
end;
else
end;
end;
procedure TSID_Chip16.GenerateWaveform(frequency,duration: TReg16; WAVFile: TStream);
const
cNumberOfChannels = 1;
cBitsPerChannel = 8;
cClockRateHz = 1e6; // 1MHz
cClockRateS = 1/cClockRateHz;
cSampleMidPoint = ($fff div 2) - 1;
type
TADSRMode = (adsrAttack,adsrDecay,adsrSustain,adsrRelease,adsrIdle);
var
TotalTime : Single; // current value of overall time in waveform generation
SIDTime : Single; // current value of time for clocking the SID chip
WAVBuffer : TWAVBuffer; // a WAV file formatted stream to write to
samplenum : LongWord; // current sample number in output WAV file
sample : LongInt;
ADSRMode : TADSRMode; // current ADSR envelope mode
ADSRVolume : Single; // current ADSR volume
ADSRTime : Single; // time for any ADSR section
SustainVol : Single; // volume level in sustain section of ADSR
ReleaseStart: Single; // the time at which ADSR sustain ends and release begins.
// (Calculated from waveform duration and ADSR envelope parameters).
Vol1,Vol2 : Single; // start/end volume for ADSR section
begin
WAVBuffer := TWAVBuffer.Create(WAVFile,duration,cNumberOfChannels,cBitsPerChannel,FSampleRateHz);
try
WAVBuffer.Reset;
SetFrequency(frequency);
ADSRMode := adsrAttack;
ADSRVolume := 0;
SustainVol := FSustainVolume/15;
ReleaseStart := duration/1000 - cDecayDelayLUT[FReleaseDelay]/1000;
SIDTime := 0;
TotalTime := 0;
ADSRTime := 0;
Vol1 := 0;
Vol2 := 1;
Gate;
for samplenum := 0 to WAVBuffer.NumberOfSamples - 1 do
begin
sample := GetOutput and $fff; //24-Bit
// write this sample to the WAV stream after converting it to (-1..+1) range
// and multiplying it by the ADSR volume
WAVBuffer.WriteSamples([((sample - cSampleMidPoint) / cSampleMidPoint) * GetADSRAmplitude]);
// update the SID chip
SIDTime := SIDTime + FSampleRateS;
// clock the SID chip as many times as required this sample step
while SIDTime >= cClockRateS do
begin
Clock;
SIDTime := SIDTime - cClockRateS;
end;
UpdateADSR;
if TotalTime >= ReleaseStart then
Release;
TotalTime := TotalTime + FSampleRateS;
end;
finally
WAVBuffer.Free;
end;
end;
end.
Code:
unit unit_wavbuffer;
{$IFDEF fpc}
{$MODE DELPHI}
{$ENDIF}
{$H+}
interface
uses
Classes;
type
TWAVBuffer = class
private
FStream : TStream;
FDuration_mSec : LongWord;
FNumberOfChannels : Byte;
FBitsPerSample : Byte;
FSampleRate : LongWord;
FNumberOfSamples : LongWord;
FDataSize : LongWord;
public
constructor Create(const AStream : TStream;
const ADuration_mSec : LongWord;
const ANumberOfChannels : Byte;
const ABitsPerSample : Byte;
const ASampleRate : LongWord);
procedure WriteWAVHeader;
procedure Reset;
procedure WriteSamples(const ASamples : array Of Single);
property NumberOfChannels: Byte read FNumberOfChannels;
property NumberOfSamples : LongWord read FNumberOfSamples;
property SampleRate : LongWord read FSampleRate;
property Duration_mSec : LongWord read FDuration_mSec;
property BitsPerSample : Byte read FBitsPerSample;
end;
implementation
constructor TWAVBuffer.Create(const AStream : TStream;
const ADuration_mSec : LongWord;
const ANumberOfChannels : Byte;
const ABitsPerSample : Byte;
const ASampleRate : LongWord);
begin
FStream := AStream;
FDuration_mSec := ADuration_mSec;
FNumberOfChannels := ANumberOfChannels;
FBitsPerSample := ABitsPerSample;
FSampleRate := ASampleRate;
if not (FNumberOfChannels in[1,2]) then FNumberOfChannels := 1;
if not (FBitsPerSample in[8,16]) then FBitsPerSample := 8;
FNumberOfSamples := (FDuration_mSec * FSampleRate) div 1000;
FDataSize := (FBitsPerSample shr 3) * FNumberOfChannels * FNumberOfSamples;
end;
procedure TWAVBuffer.WriteWAVHeader;
const
WAVE_FORMAT_PCM = 1;
RiffId : AnsiString = 'RIFF';
WaveId : AnsiString = 'WAVE';
FmtId : AnsiString = 'fmt ';
DataId : AnsiString = 'data';
type
TWaveHeader = packed record
wFormatTag : Word; // format type
nChannels : Word; // number of channels (i.e. mono, stereo, etc.)
nSamplesPerSec : LongWord; // sample rate
nAvgBytesPerSec : LongWord; // for buffer estimation
nBlockAlign : Word; // block size of data
wBitsPerSample : Word; // number of bits per sample of mono data
cbSize : Word; // the count in bytes of the size of
end;
var
WaveHeader : TWaveHeader;
RiffCount : Integer;
TempInt : LongWord;
begin
// initialize wave header
WaveHeader.wFormatTag := WAVE_FORMAT_PCM;
WaveHeader.nChannels := FNumberOfChannels;
WaveHeader.nSamplesPerSec := FSampleRate;
WaveHeader.wBitsPerSample := FBitsPerSample;
WaveHeader.nBlockAlign := WaveHeader.nChannels * WaveHeader.wBitsPerSample shr 3;
WaveHeader.nAvgBytesPerSec := WaveHeader.nSamplesPerSec * WaveHeader.nBlockAlign;
WaveHeader.cbSize := 0;
{Calculate length of sound data and of file data}
RiffCount := Length(WaveId) + Length(FmtId) + SizeOf(LongWord) +
SizeOf(TWaveHeader) + Length(DataId) + SizeOf(LongWord) + FDataSize; // file data
{write out the wave header}
FStream.Write(RiffId[1] , 4); // 'RIFF'
FStream.Write(RiffCount , SizeOf(LongWord)); // file data size
FStream.Write(WaveId[1] , Length(WaveId)); // 'WAVE'
FStream.Write(FmtId[1] , Length(FmtId)); // 'fmt '
TempInt := SizeOf(TWaveHeader);
FStream.Write(TempInt , SizeOf(LongWord)); // TWaveFormat data size
FStream.Write(WaveHeader , SizeOf(WaveHeader)); // WaveFormatEx record
FStream.Write(DataId[1] , Length(DataId)); // 'data'
FStream.Write(FDataSize , SizeOf(LongWord)); // sound data size
end;
procedure TWAVBuffer.Reset;
begin
FStream.Seek(0,soFromBeginning);
WriteWAVHeader;
end;
procedure TWAVBuffer.WriteSamples(const aSamples : array of Single);
var
Sample_8Bit : Byte;
Sample_16Bit : SmallInt;
Sample : Single;
i : Integer;
begin
for i := 0 To High(ASamples) do
begin
Sample := ASamples[i];
// clip sample to between [-1,+1]
if Sample < -1.0 then Sample := -1.0
else if Sample > +1.0 then Sample := +1.0;
// write sample to stream
if FBitsPerSample = 8 then
begin
Sample_8Bit := 127 + Trunc(127 * Sample);
FStream.Write(Sample_8Bit,SizeOf(Sample_8Bit));
end
else
if FBitsPerSample = 16 then
begin
Sample_16Bit := Trunc(32767 * Sample);
FStream.Write(Sample_16Bit,SizeOf(Sample_16Bit));
end;
end;
end;
end.
![]() LOL! Now I will have to make a Chip16 emulator too as I have no excuses anymore!! haha cheers, Paul |
|
|
|
|
|
#85 |
|
Sober coder
![]() ![]() ![]() Join Date: Aug 2010
Location: London, UK
Posts: 433
|
Very nice, thank you very much! Could you possibly make a couple more sounds/tunes just to see what is possible with this sound generator?
__________________
|
|
|
|
|
|
#86 |
|
Registered User
![]() ![]() Join Date: Sep 2011
Location: Australia, Tasmania
Posts: 180
|
Ok, I will see what I can whip up ASAP ![]() EDIT: I based my SID around the C64 emulator code in the reSID sound emulator...I used the waveform parts, but worked out my own ADSR stuff. cheers, Paul Last edited by paul_nicholls; December 2nd, 2011 at 10:22.. |
|
|
|
|
|
#87 |
|
Registered User
![]() ![]() Join Date: Sep 2011
Location: Australia, Tasmania
Posts: 180
|
Hey all, I have attached the source + .exe of a test program for my Chip16 SID unit (written using Delphi 2010)... SIDTest.zip (~406KB) Have a play, I hope you find it useful ![]() You should be able to get a wide range of sounds generated, just experiment. Oh, I had slightly changed the GenerateWaveform method in the SID unit (in the zip file) so it uses the release delay on the end of the given duration to calculate the total sound duration which makes more sense ![]() cheers, Paul |
|
|
|
|
|
#88 |
|
Sober coder
![]() ![]() ![]() Join Date: Aug 2010
Location: London, UK
Posts: 433
|
Very nice, thank you very much! I was going to suggest making some reference sounds to calibrate people's sound emu to, but (assuming this works correctly) we don't seem to need that anymore! Oh, and just a question, in your program there are separate note and octave types... how do these relate to the "tone" specified in the new spec?
__________________
Last edited by tykel; December 6th, 2011 at 08:57.. |
|
|
|
|
|
#89 | |
|
Registered User
![]() ![]() Join Date: Sep 2011
Location: Australia, Tasmania
Posts: 180
|
Quote:
I calculated the note frequencies from a page similar to this: http://www.phy.mtu.edu/~suits/notefreqs.html using equations like here: http://www.phy.mtu.edu/~suits/NoteFreqCalcs.html cheers, Paul |
|
|
|
|
|
|
#90 |
|
Sober coder
![]() ![]() ![]() Join Date: Aug 2010
Location: London, UK
Posts: 433
|
Great, just what I was looking for. Thanks again. (I think some of this Q/A will be useful to prospective emu-makers now I look at it!)
__________________
|
|
|
|
|
|
#91 |
|
Registered User
![]() ![]() Join Date: Sep 2011
Location: Australia, Tasmania
Posts: 180
|
No worries tykel ![]() I have gotten so much information from the internet, I like to give back too
|
|
|
|
|
|
#92 |
|
Registered User
Join Date: Nov 2010
Location: UK
Posts: 9
|
I recently started to implement my own chip 16 emulator. I have previously made a chip 8 emulator and wanted something more challenging. Anyway, since it just hit version 1.0 wouldn't it make sense to add a cpuid function of sorts allowing to get the emulators implemented version?
|
|
|
|
|
|
#93 | |
|
Sober coder
![]() ![]() ![]() Join Date: Aug 2010
Location: London, UK
Posts: 433
|
Quote:
A CPUID function would add unecessary complexity in my opinion. I think that games/demos for the system should use all the features they want, and there should just be an effort to keep the emu's up-to-date. Also, the big changes to the spec are done now. I think it is unlikely anything major will be coming soon, until there is widespread adoption of spec 1.0 anyway. What I would find interesting, though, is to define a Chip16 ROM file format, which would contain various metadata -- like the spec version -- and the emulator could then just complain if its version is below the ROM's. Thoughts?
__________________
|
|
|
|
|
|
|
#94 |
|
Linux's worst nightmare..
![]() ![]() ![]() ![]() ![]() Join Date: Feb 2004
Location: USA
Posts: 1,505
|
Now that there is proper sound im tempted to jump back into the fray and update MSChip16. But Im trying to stop java whoring and get a proper grasp of c++...
__________________
OS: WinXP Professional Service Pack 3 CPU: Intel pentium 4 3.0GHz Video: Nvidia Geforce 8400GS Sound: ASUS Xonar DS 7.1 Channels 24-bit 192KHz PCI Interface Audio Card Memory: 512 MB HD: [C:] 140.36/449.09 GB Connection: Marvell Yukon 88E8053 PCI-E Gigabit Ethernet Controller |
|
|
|
|
|
#95 |
|
Sober coder
![]() ![]() ![]() Join Date: Aug 2010
Location: London, UK
Posts: 433
|
So for a potential ROM format, here is an initial suggestion: Code:
0000h: 'CH16' = magic number 0004h: Spec version (3-char ASCII, eg '1.0' or '0.7') 0007h: Reserved 0008h: rom length (excl. header) 000Ch: start address (defaults to 0) 0010h: MD5 checksum (excl. header) 0020h: Start of binary
__________________
|
|
|
|
|
|
#96 |
|
Registered User
![]() ![]() Join Date: Sep 2011
Location: Australia, Tasmania
Posts: 180
|
I like this idea, and the potential ROM format...but why have a reserved part - to make it more official looking? LOL
|
|
|
|
|
|
#97 |
|
Registered User
![]() ![]() Join Date: Sep 2011
Location: Australia, Tasmania
Posts: 180
|
or is it to make the ROM format header exactly 32 bytes?
|
|
|
|
|
|
#98 |
|
Registered User
Join Date: Aug 2010
Location: Russia, Moscow
Posts: 48
|
I like idea with ROM-header but i don't understand why header has so big size? My header version is: Code:
0000h: 'CH16' = magic number 0004h: Reserved (allways 0) 0005h: Spec version (1-byte. The first 4-bits are major version and last 4-bits - minor version. So, we can code version from v0.0 to v16.16') 0006h: rom length (excl. header) For future spec, size might be over 64kb. 000Ah: start address (default to 0) Max: 0xFFFF 000Ch: CRC-32 checksum; polynom 0x04C11DB7 (excl. header) 0010h: start of binary code Last edited by tronix286; December 13th, 2011 at 08:15.. |
|
|
|
|
|
#99 | |
|
Registered User
![]() ![]() Join Date: Sep 2011
Location: Australia, Tasmania
Posts: 180
|
Quote:
|
|
|
|
|
|
|
#100 |
|
PCSX2 Coder
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Join Date: Jan 2004
Location: Plymouth, UK
Posts: 10,037
|
quick question at the fear of looking like an idiot, does this mean we will only load in to memory the data from the start of the binary? or should the default start address actually be 0020h or 0010h (depending on the 16bit or 32bit header)?
__________________
http://www.pcsx2.net Intel i7 920 @ 3.4Ghz, POV GTX 570 1.3Gb, 1.8Tb HD space, 6Gb OCZ Reaper PC3-14400 Triple Channel Dont PM me for help, use the forums, thats what its for! My Chip16 Emulator RefChip16 http://code.google.com/p/refchip16/
|
|
|
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|