It makes the correct frequencies, but still doesn't dial numbers on a phone.
The sound is a little different to listen to.. tinny like a car horn, yet in tune.
If you play high quality recorded DTMF sounds the phone DOES dial,
anyone can do that with chunky code that stores the samples.
There must be still some problem with this code.
If anyone sorts it out I'd appreciate the solution.
Code: Select all
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspaudiolib.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <pspctrl.h>
PSP_MODULE_INFO("DTMF", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU);
#define printf pspDebugScreenPrintf
int ix; // counter
int done; // exit flag
void dump_threadstatus(void);
int exit_callback(int arg1, int arg2, void *common) {
done = 1;
sceKernelExitGame();
return 0;
}
int CallbackThread(SceSize args, void *argp) {
int cbid;
cbid = sceKernelCreateCallback("Exit Callback", (void *) exit_callback, NULL);
sceKernelRegisterExitCallback(cbid);
sceKernelSleepThreadCB();
return 0;
}
int SetupCallbacks(void) {
int thid = 0;
thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, 0, 0);
if(thid >= 0){sceKernelStartThread(thid, 0, 0);}
return thid;
}
int pspAudioInit();
void pspAudioEndPre();
void pspAudioEnd();
#define SAMPLE_COUNT 0x10000
float sample[SAMPLE_COUNT];
#define SAMPLE_RATE 44100
#define OCTAVE_COUNT 6
#define NOTE_END -2
#define NOTE_PAUSE -1
float octaves[OCTAVE_COUNT][12];
typedef struct {
int note;
int octave;
int duration;
} Note_t;
typedef struct {
Note_t currentNote;
int noteIndex;
int currentTime;
float currentsampleIndex;
float currentsampleIncrement;
} ChannelState_t;
ChannelState_t channelStates[3];
#define EIGHT_NOTE(note, octave, duration) { note, octave, SAMPLE_RATE * duration / 8}
Note_t channel0[] = {
EIGHT_NOTE(3, 0, 4),
EIGHT_NOTE(0, 0, 4),
EIGHT_NOTE(0, 0, 4),
EIGHT_NOTE(0, 0, 4),
EIGHT_NOTE(1, 0, 4),
EIGHT_NOTE(1, 0, 4),
EIGHT_NOTE(1, 0, 4),
EIGHT_NOTE(2, 0, 4),
EIGHT_NOTE(2, 0, 4),
EIGHT_NOTE(2, 0, 4),
EIGHT_NOTE(3, 0, 4),
EIGHT_NOTE(3, 0, 4),
EIGHT_NOTE(-1, 0, 4),
{ NOTE_END, 0, 0 }
};
Note_t channel1[] = {
EIGHT_NOTE(5, 0, 4),
EIGHT_NOTE(4, 0, 4),
EIGHT_NOTE(5, 0, 4),
EIGHT_NOTE(6, 0, 4),
EIGHT_NOTE(4, 0, 4),
EIGHT_NOTE(5, 0, 4),
EIGHT_NOTE(6, 0, 4),
EIGHT_NOTE(4, 0, 4),
EIGHT_NOTE(5, 0, 4),
EIGHT_NOTE(6, 0, 4),
EIGHT_NOTE(4, 0, 4),
EIGHT_NOTE(6, 0, 4),
EIGHT_NOTE(-1, 0, 4),
{ NOTE_END, 0, 0 }
};
Note_t* channels[] = { channel0, channel1 };
void nextNote(int channel)
{
ChannelState_t* state = &channelStates[channel];
state->currentNote = channels[channel][state->noteIndex];
state->currentTime = 0;
state->currentsampleIndex = 0;
int note = state->currentNote.note;
if (note == NOTE_PAUSE) {
state->currentsampleIncrement = 0;
} else {
state->currentsampleIncrement = octaves[state->currentNote.octave][note] * ((float) SAMPLE_COUNT) / ((float) SAMPLE_RATE);
}
state->noteIndex++;
if (channels[channel][state->noteIndex].note == NOTE_END) state->noteIndex = 0;
}
// calculate current value of attack/delay/sustain/release envelope
float adsr(float time, float duration) {
if (time < 0.0) return 0.0;
const float attack = 0.0;
const float decay = 0.0;
const float sustain = 0.5;
const float release = 0.0;
if (time < attack) return time / attack;
if (time < decay) return (decay - time) / decay * (1.0 - sustain) + sustain;
if (time < duration) return sustain;
time -= duration;
if (time < release) return (release - time) / release * sustain;
return 0.0;
}
void audioOutCallback(int channel, unsigned short* buf, unsigned int reqn)
{
ChannelState_t* state = &channelStates[channel];
unsigned int i;
for (i = 0; i < reqn; i++) {
float time = ((float) state->currentTime) / ((float) SAMPLE_RATE);
if (state->currentTime++ == state->currentNote.duration);
float value;
if (state->currentsampleIncrement == 0.0) {
value = 0.0;
} else {
value = sample[(int)state->currentsampleIndex] * adsr(time, ((float) state->currentNote.duration) / ((float) SAMPLE_RATE));
value *= (float) 0x7000;
state->currentsampleIndex += state->currentsampleIncrement;
if (state->currentsampleIndex >= SAMPLE_COUNT) state->currentsampleIndex -= (float) SAMPLE_COUNT;
}
buf[0] = value;
buf[1] = value;
buf += 2;
}
}
void audioOutCallback0(void *buf, unsigned int reqn, void *userdata) { audioOutCallback(0, buf, reqn); }
void audioOutCallback1(void *buf, unsigned int reqn, void *userdata) { audioOutCallback(1, buf, reqn); }
void createPitches(float base, float* target)
{
target[0] = 697;
target[1] = 770;
target[2] = 852;
target[3] = 941;
target[4] = 1209;
target[5] = 1336;
target[6] = 1477;
target[7] = 1633;
target[8] = 1;
target[9] = 1;
target[10] = 1;
target[11] = 1;
target[12] = 1;
}
int main(void)
{
pspDebugScreenInit();
SetupCallbacks();
printf("DTMF Touch Tone Generator by Art 2008!\n");
printf("Based on Polyphonic sample by Shine\n");
int i;
int maxAt = SAMPLE_COUNT / 16;
for (i = 0; i < SAMPLE_COUNT; i++) {
float value;
if (i < maxAt) {
value = ((float) i) / ((float) maxAt) * 2.0 - 1.0;
} else {
value = 1.0 - ((float) (i - maxAt)) / ((float) (SAMPLE_COUNT - maxAt)) * 2.0;
}
sample[i] = value;
}
float base = 0.0;
for (i = 0; i < OCTAVE_COUNT; i++) {
createPitches(base, octaves[i]);
base *= 2;
}
channelStates[0].noteIndex = 0;// nextNote(0);
channelStates[1].noteIndex = 0;// nextNote(1);
pspAudioInit();
pspAudioSetVolume(0, 0x5000, 0x5000);
pspAudioSetVolume(1, 0x5000, 0x5000);
pspAudioSetChannelCallback(0, audioOutCallback0, NULL);
pspAudioSetChannelCallback(1, audioOutCallback1, NULL);
while (done == 0) {
SceCtrlData xpad;
sceCtrlSetSamplingMode(1);
sceCtrlPeekBufferPositive(&xpad, 1);
if(xpad.Buttons & PSP_CTRL_CROSS) {
channelStates[0].noteIndex = 1;nextNote(0);
channelStates[1].noteIndex = 1;nextNote(1);
}
if(xpad.Buttons & PSP_CTRL_CIRCLE) {
channelStates[0].noteIndex = 2;nextNote(0);
channelStates[1].noteIndex = 2;nextNote(1);
}
if(xpad.Buttons & PSP_CTRL_TRIANGLE) {
channelStates[0].noteIndex = 3;nextNote(0);
channelStates[1].noteIndex = 3;nextNote(1);
}
if(xpad.Buttons & PSP_CTRL_SQUARE) {
channelStates[0].noteIndex = 4;nextNote(0);
channelStates[1].noteIndex = 4;nextNote(1);
}
if(xpad.Buttons & PSP_CTRL_DOWN) {
channelStates[0].noteIndex = 5;nextNote(0);
channelStates[1].noteIndex = 5;nextNote(1);
}
if(xpad.Buttons & PSP_CTRL_RIGHT) {
channelStates[0].noteIndex = 6;nextNote(0);
channelStates[1].noteIndex = 6;nextNote(1);
}
if(xpad.Buttons & PSP_CTRL_UP) {
channelStates[0].noteIndex = 7;nextNote(0);
channelStates[1].noteIndex = 7;nextNote(1);
}
if(xpad.Buttons & PSP_CTRL_LEFT) {
channelStates[0].noteIndex = 8;nextNote(0);
channelStates[1].noteIndex = 8;nextNote(1);
}
if(xpad.Buttons & PSP_CTRL_LTRIGGER) {
channelStates[0].noteIndex = 9;nextNote(0);
channelStates[1].noteIndex = 9;nextNote(1);
}
if(xpad.Buttons & PSP_CTRL_RTRIGGER) {
channelStates[0].noteIndex = 0;nextNote(0);
channelStates[1].noteIndex = 0;nextNote(1);
}
} // while
done = 1;
sceKernelExitGame();
return 0;
}
Cheers, Art.