Scope graphing rewrite: speech/music merged, allows 8- or 16-bit, auto-adjust level; bug #1064
git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@3181 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
Changes towards version 0.7:
|
Changes towards version 0.7:
|
||||||
|
- Allow any sound data format to be graphed by comm oscilloscope; also
|
||||||
|
auto-adjust the scope for different gain levels (bug #1064) - Alex
|
||||||
- Game settings Quit menu now delegates to F10 quit (bug #462) - Alex
|
- Game settings Quit menu now delegates to F10 quit (bug #462) - Alex
|
||||||
- Do not pause the game in places where not relevant (bug #984) - Alex
|
- Do not pause the game in places where not relevant (bug #984) - Alex
|
||||||
- Fixed crashes and potential weirdness when loading savegames from
|
- Fixed crashes and potential weirdness when loading savegames from
|
||||||
|
|||||||
@@ -237,3 +237,31 @@ audio_BufferData (audio_Object bufobj, uint32 format, void* data,
|
|||||||
audiodrv.BufferData (bufobj, audiodrv.EnumLookup[format], data, size,
|
audiodrv.BufferData (bufobj, audiodrv.EnumLookup[format], data, size,
|
||||||
freq);
|
freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
audio_GetFormatInfo (uint32 format, int *channels, int *sample_size)
|
||||||
|
{
|
||||||
|
switch (format)
|
||||||
|
{
|
||||||
|
case audio_FORMAT_MONO8:
|
||||||
|
*channels = 1;
|
||||||
|
*sample_size = sizeof (uint8);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case audio_FORMAT_STEREO8:
|
||||||
|
*channels = 2;
|
||||||
|
*sample_size = sizeof (uint8);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case audio_FORMAT_MONO16:
|
||||||
|
*channels = 1;
|
||||||
|
*sample_size = sizeof (sint16);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case audio_FORMAT_STEREO16:
|
||||||
|
*channels = 2;
|
||||||
|
*sample_size = sizeof (sint16);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -164,4 +164,6 @@ void audio_GetBufferi (audio_Object bufobj, audio_BufferProp pname,
|
|||||||
void audio_BufferData (audio_Object bufobj, uint32 format, void* data,
|
void audio_BufferData (audio_Object bufobj, uint32 format, void* data,
|
||||||
uint32 size, uint32 freq);
|
uint32 size, uint32 freq);
|
||||||
|
|
||||||
|
bool audio_GetFormatInfo (uint32 format, int *channels, int *sample_size);
|
||||||
|
|
||||||
#endif /* _AUDIOCORE_H */
|
#endif /* _AUDIOCORE_H */
|
||||||
|
|||||||
@@ -75,11 +75,11 @@ typedef struct tfb_soundsource
|
|||||||
sint32 start_time;
|
sint32 start_time;
|
||||||
void *positional_object;
|
void *positional_object;
|
||||||
|
|
||||||
// for oscilloscope
|
// Cyclic waveform buffer for oscilloscope
|
||||||
void *sbuffer;
|
void *sbuffer;
|
||||||
uint32 sbuf_start;
|
uint32 sbuf_start; // cyclic buffer tail (confusing, eh?)
|
||||||
uint32 sbuf_size;
|
uint32 sbuf_size;
|
||||||
uint32 sbuf_offset;
|
uint32 sbuf_offset; // cyclic buffer head
|
||||||
uint32 sbuf_lasttime;
|
uint32 sbuf_lasttime;
|
||||||
// keep track for paused tracks
|
// keep track for paused tracks
|
||||||
uint32 pause_time;
|
uint32 pause_time;
|
||||||
|
|||||||
@@ -449,3 +449,175 @@ StreamDecoderTaskFunc (void *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline sint32
|
||||||
|
readSoundSample (void *ptr, int sample_size)
|
||||||
|
{
|
||||||
|
if (sample_size == sizeof (uint8))
|
||||||
|
return (*(uint8*)ptr - 128) << 8;
|
||||||
|
else
|
||||||
|
return *(sint16*)ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Graphs the current sound data for the oscilloscope.
|
||||||
|
// Includes a rudimentary automatic gain control (AGC) to properly graph
|
||||||
|
// the streams at different gain levels (based on running average).
|
||||||
|
// We use AGC because different pieces of music and speech can easily be
|
||||||
|
// at very different gain levels, because the game is moddable.
|
||||||
|
int
|
||||||
|
GraphForegroundStream (uint8 *data, sint32 width, sint32 height)
|
||||||
|
{
|
||||||
|
int source_num;
|
||||||
|
TFB_SoundSource *source;
|
||||||
|
TFB_SoundDecoder *decoder;
|
||||||
|
int channels;
|
||||||
|
int sample_size;
|
||||||
|
int full_sample;
|
||||||
|
int step;
|
||||||
|
long played_time;
|
||||||
|
long delta;
|
||||||
|
uint8 *sbuffer;
|
||||||
|
unsigned long pos;
|
||||||
|
int scale;
|
||||||
|
sint32 i;
|
||||||
|
// AGC variables
|
||||||
|
#define DEF_PAGE_MAX 28000
|
||||||
|
#define AGC_PAGE_COUNT 16
|
||||||
|
static int page_sum = DEF_PAGE_MAX * AGC_PAGE_COUNT;
|
||||||
|
static int pages[AGC_PAGE_COUNT] =
|
||||||
|
{
|
||||||
|
DEF_PAGE_MAX, DEF_PAGE_MAX, DEF_PAGE_MAX, DEF_PAGE_MAX,
|
||||||
|
DEF_PAGE_MAX, DEF_PAGE_MAX, DEF_PAGE_MAX, DEF_PAGE_MAX,
|
||||||
|
DEF_PAGE_MAX, DEF_PAGE_MAX, DEF_PAGE_MAX, DEF_PAGE_MAX,
|
||||||
|
DEF_PAGE_MAX, DEF_PAGE_MAX, DEF_PAGE_MAX, DEF_PAGE_MAX,
|
||||||
|
};
|
||||||
|
static int page_head;
|
||||||
|
#define AGC_FRAME_COUNT 8
|
||||||
|
static int frame_sum;
|
||||||
|
static int frames;
|
||||||
|
static int avg_amp = DEF_PAGE_MAX; // running amplitude (sort of) average
|
||||||
|
int target_amp;
|
||||||
|
int max_a;
|
||||||
|
#define VAD_MIN_ENERGY 100
|
||||||
|
long energy;
|
||||||
|
|
||||||
|
|
||||||
|
if (speechVolumeScale != 0.0f)
|
||||||
|
{ // Use speech waveform when speech is enabled
|
||||||
|
source_num = SPEECH_SOURCE;
|
||||||
|
// Step is picked experimentally. Using step of 1 sample at 11025Hz,
|
||||||
|
// because human speech is mostly in the low frequencies, and it looks
|
||||||
|
// better this way.
|
||||||
|
step = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (musicVolumeScale != 0.0f)
|
||||||
|
{ // Use music waveform when speech is disabled
|
||||||
|
source_num = MUSIC_SOURCE;
|
||||||
|
// Step is picked experimentally. Using step of 4 samples at 11025Hz.
|
||||||
|
// It looks better this way.
|
||||||
|
step = 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
source = &soundSource[source_num];
|
||||||
|
LockMutex (source->stream_mutex);
|
||||||
|
if (!PlayingStream (source_num) || !source->sample
|
||||||
|
|| !source->sample->decoder || !source->sbuffer
|
||||||
|
|| source->sbuf_size == 0)
|
||||||
|
{ // We don't have data to return, oh well.
|
||||||
|
UnlockMutex (source->stream_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
decoder = source->sample->decoder;
|
||||||
|
|
||||||
|
assert (audio_GetFormatInfo (decoder->format, &channels, &sample_size));
|
||||||
|
full_sample = channels * sample_size;
|
||||||
|
|
||||||
|
// See how far into the buffer we should be now
|
||||||
|
played_time = GetTimeCounter () - source->sbuf_lasttime;
|
||||||
|
delta = played_time * decoder->frequency * full_sample / ONE_SECOND;
|
||||||
|
// align delta to sample start
|
||||||
|
delta = delta & ~(full_sample - 1);
|
||||||
|
|
||||||
|
if (delta < 0)
|
||||||
|
{
|
||||||
|
log_add (log_Debug, "GraphForegroundStream(): something is messed"
|
||||||
|
" with timing, delta %ld", delta);
|
||||||
|
delta = 0;
|
||||||
|
}
|
||||||
|
else if (delta > (long)source->sbuf_size)
|
||||||
|
{ // Stream decoder task has just had a heart attack, not much we can do
|
||||||
|
delta = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step is in 11025 Hz units, so we need to adjust to source frequency
|
||||||
|
step = decoder->frequency * step / 11025;
|
||||||
|
if (step == 0)
|
||||||
|
step = 1;
|
||||||
|
step *= full_sample;
|
||||||
|
|
||||||
|
sbuffer = source->sbuffer;
|
||||||
|
pos = source->sbuf_offset + delta;
|
||||||
|
|
||||||
|
// We are not basing the scaling factor on signal energy, because we
|
||||||
|
// want it to *look* pretty instead of sounding nice and even
|
||||||
|
target_amp = (height >> 1) >> 1;
|
||||||
|
scale = avg_amp / target_amp;
|
||||||
|
|
||||||
|
max_a = 0;
|
||||||
|
energy = 0;
|
||||||
|
for (i = 0; i < width; ++i, pos += step)
|
||||||
|
{
|
||||||
|
sint32 s;
|
||||||
|
int t;
|
||||||
|
|
||||||
|
pos %= source->sbuf_size;
|
||||||
|
|
||||||
|
s = readSoundSample (sbuffer + pos, sample_size);
|
||||||
|
if (channels > 1)
|
||||||
|
s += readSoundSample (sbuffer + pos + sample_size, sample_size);
|
||||||
|
|
||||||
|
energy += (s * s) / 0x10000;
|
||||||
|
t = abs(s);
|
||||||
|
if (t > max_a)
|
||||||
|
max_a = t;
|
||||||
|
|
||||||
|
s = (s / scale) + (height >> 1);
|
||||||
|
if (s < 0)
|
||||||
|
s = 0;
|
||||||
|
else if (s > height - 1)
|
||||||
|
s = height - 1;
|
||||||
|
|
||||||
|
data[i] = s;
|
||||||
|
}
|
||||||
|
energy /= width;
|
||||||
|
|
||||||
|
// Very basic VAD. We don't want to count speech pauses in the average
|
||||||
|
if (energy > VAD_MIN_ENERGY)
|
||||||
|
{
|
||||||
|
// Record the maximum amplitude (sort of)
|
||||||
|
frame_sum += max_a;
|
||||||
|
++frames;
|
||||||
|
if (frames == 8)
|
||||||
|
{ // Got a full page
|
||||||
|
frame_sum /= AGC_FRAME_COUNT;
|
||||||
|
// Record the page
|
||||||
|
page_sum -= pages[page_head];
|
||||||
|
page_sum += frame_sum;
|
||||||
|
pages[page_head] = frame_sum;
|
||||||
|
page_head = (page_head + 1) % AGC_PAGE_COUNT;
|
||||||
|
|
||||||
|
frame_sum = 0;
|
||||||
|
frames = 0;
|
||||||
|
|
||||||
|
avg_amp = page_sum / AGC_PAGE_COUNT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UnlockMutex (source->stream_mutex);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,4 +30,6 @@ TFB_SoundTag* FindTaggedBuffer (TFB_SoundSample* sample, audio_Object buffer);
|
|||||||
void TFB_ClearBufferTag (TFB_SoundTag* ptag);
|
void TFB_ClearBufferTag (TFB_SoundTag* ptag);
|
||||||
void TFB_TagBuffer (TFB_SoundSample* sample, audio_Object buffer, void* data);
|
void TFB_TagBuffer (TFB_SoundSample* sample, audio_Object buffer, void* data);
|
||||||
|
|
||||||
|
int GraphForegroundStream (uint8 *data, sint32 width, sint32 height);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -19,9 +19,7 @@
|
|||||||
#include "libs/sound/trackint.h"
|
#include "libs/sound/trackint.h"
|
||||||
#include "libs/log.h"
|
#include "libs/log.h"
|
||||||
#include "comm.h"
|
#include "comm.h"
|
||||||
#include "sis.h"
|
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include <assert.h>
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
@@ -821,179 +819,6 @@ FastForward_Page ()
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// processes sound data to oscilloscope
|
|
||||||
int
|
|
||||||
GetSoundData (void *data)
|
|
||||||
{
|
|
||||||
// XXX: These two variants are begging to be merged
|
|
||||||
if (speechVolumeScale != 0.0f)
|
|
||||||
{
|
|
||||||
// speech is enabled
|
|
||||||
|
|
||||||
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
|
|
||||||
if (soundSource[SPEECH_SOURCE].sample && soundSource[SPEECH_SOURCE].sample->decoder &&
|
|
||||||
PlayingStream (SPEECH_SOURCE) && soundSource[SPEECH_SOURCE].sbuffer &&
|
|
||||||
soundSource[SPEECH_SOURCE].sbuf_size > 0)
|
|
||||||
{
|
|
||||||
float played_time = (GetTimeCounter () - soundSource[SPEECH_SOURCE].sbuf_lasttime) /
|
|
||||||
(float)ONE_SECOND;
|
|
||||||
long delta = (int) (played_time * (float)soundSource[SPEECH_SOURCE].
|
|
||||||
sample->decoder->frequency * 2.0f);
|
|
||||||
unsigned long pos;
|
|
||||||
int i;
|
|
||||||
int step;
|
|
||||||
UBYTE *scopedata = (UBYTE *) data;
|
|
||||||
UBYTE *sbuffer = soundSource[SPEECH_SOURCE].sbuffer;
|
|
||||||
|
|
||||||
assert (soundSource[SPEECH_SOURCE].sample->decoder->frequency >= 11025);
|
|
||||||
assert (soundSource[SPEECH_SOURCE].sample->decoder->format == audio_FORMAT_MONO16);
|
|
||||||
|
|
||||||
// Using step of 1 sample at 11025Hz, because the human speech
|
|
||||||
// is mostly in the low frequencies
|
|
||||||
step = soundSource[SPEECH_SOURCE].sample->decoder->frequency * 2 / 11025;
|
|
||||||
step = (step + 1) & ~1;
|
|
||||||
|
|
||||||
if (delta < 0)
|
|
||||||
{
|
|
||||||
log_add (log_Debug, "GetSoundData(): something's messed"
|
|
||||||
" with timing, delta %ld", delta);
|
|
||||||
delta = 0;
|
|
||||||
}
|
|
||||||
else if (delta > (int)(soundSource[SPEECH_SOURCE].sbuf_size * 2))
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
log_add (log_Debug, "GetSoundData(): something's messed"
|
|
||||||
" with timing, delta %d", delta);
|
|
||||||
#endif
|
|
||||||
delta = 0;
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
log_add (log_Debug, "played_data %d total_decoded %d delta %d",
|
|
||||||
played_data, soundSource[SPEECH_SOURCE].total_decoded,
|
|
||||||
delta);
|
|
||||||
#endif
|
|
||||||
pos = soundSource[SPEECH_SOURCE].sbuf_offset + delta;
|
|
||||||
if (pos % 2 == 1)
|
|
||||||
pos++;
|
|
||||||
|
|
||||||
// pos is an unsigned data type; this assertion cannot fail!
|
|
||||||
// assert (pos >= 0);
|
|
||||||
|
|
||||||
for (i = 0; i < RADAR_WIDTH - 2; ++i)
|
|
||||||
{
|
|
||||||
SDWORD s;
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
if (pos >= soundSource[SPEECH_SOURCE].sbuf_size)
|
|
||||||
pos = pos - soundSource[SPEECH_SOURCE].sbuf_size;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
s = *(SWORD*) (&sbuffer[pos]);
|
|
||||||
s = (s / 1360) + (RADAR_HEIGHT >> 1);
|
|
||||||
if (s < 1)
|
|
||||||
s = 1;
|
|
||||||
else if (s > RADAR_HEIGHT - 2)
|
|
||||||
s = RADAR_HEIGHT - 2;
|
|
||||||
scopedata[i] = (UBYTE) s;
|
|
||||||
|
|
||||||
pos += step;
|
|
||||||
}
|
|
||||||
|
|
||||||
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
|
|
||||||
}
|
|
||||||
else if (musicVolumeScale != 0.0f)
|
|
||||||
{
|
|
||||||
// speech is disabled but music is not so process it instead
|
|
||||||
|
|
||||||
LockMutex (soundSource[MUSIC_SOURCE].stream_mutex);
|
|
||||||
if (soundSource[MUSIC_SOURCE].sample && soundSource[MUSIC_SOURCE].sample->decoder &&
|
|
||||||
PlayingStream (MUSIC_SOURCE) && soundSource[MUSIC_SOURCE].sbuffer &&
|
|
||||||
soundSource[MUSIC_SOURCE].sbuf_size > 0)
|
|
||||||
{
|
|
||||||
float played_time = (GetTimeCounter () - soundSource[MUSIC_SOURCE].sbuf_lasttime) /
|
|
||||||
(float)ONE_SECOND;
|
|
||||||
int delta = (int) (played_time * (float)soundSource[MUSIC_SOURCE].
|
|
||||||
sample->decoder->frequency * 4.0f);
|
|
||||||
unsigned long pos;
|
|
||||||
int i, step;
|
|
||||||
UBYTE *scopedata = (UBYTE *) data;
|
|
||||||
UBYTE *sbuffer = soundSource[MUSIC_SOURCE].sbuffer;
|
|
||||||
|
|
||||||
assert (soundSource[MUSIC_SOURCE].sample->decoder->frequency >= 11025);
|
|
||||||
assert (soundSource[MUSIC_SOURCE].sample->decoder->format == audio_FORMAT_STEREO16);
|
|
||||||
|
|
||||||
// Using step of 4 samples at 11025Hz for the music
|
|
||||||
step = soundSource[MUSIC_SOURCE].sample->decoder->frequency / 11025 * 16;
|
|
||||||
if (step % 2 == 1)
|
|
||||||
step++;
|
|
||||||
|
|
||||||
if (delta < 0)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
log_add (log_Debug, "GetSoundData(): something's messed"
|
|
||||||
" with timing, delta %d", delta);
|
|
||||||
#endif
|
|
||||||
delta = 0;
|
|
||||||
}
|
|
||||||
else if (delta > (int)(soundSource[MUSIC_SOURCE].sbuf_size * 2))
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
log_add (log_Debug, "GetSoundData(): something's messed"
|
|
||||||
" with timing, delta %d", delta);
|
|
||||||
#endif
|
|
||||||
delta = 0;
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
log_add (log_Debug, "played_data %d total_decoded %d delta %d",
|
|
||||||
played_data, soundSource[MUSIC_SOURCE].total_decoded,
|
|
||||||
delta);
|
|
||||||
#endif
|
|
||||||
pos = soundSource[MUSIC_SOURCE].sbuf_offset + delta;
|
|
||||||
if (pos % 2 == 1)
|
|
||||||
pos++;
|
|
||||||
|
|
||||||
// pos is an unsigned type; this assertion cannot fail!
|
|
||||||
// assert (pos >= 0);
|
|
||||||
|
|
||||||
for (i = 0; i < RADAR_WIDTH - 2; ++i)
|
|
||||||
{
|
|
||||||
SDWORD s;
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
if (pos >= soundSource[MUSIC_SOURCE].sbuf_size)
|
|
||||||
pos = pos - soundSource[MUSIC_SOURCE].sbuf_size;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
s = (*(SWORD*)(&sbuffer[pos])) + (*(SWORD*)(&sbuffer[pos + 2]));
|
|
||||||
|
|
||||||
s = (s / 1800) + (RADAR_HEIGHT >> 1);
|
|
||||||
if (s < 1)
|
|
||||||
s = 1;
|
|
||||||
else if (s > RADAR_HEIGHT - 2)
|
|
||||||
s = RADAR_HEIGHT - 2;
|
|
||||||
scopedata[i] = (UBYTE) s;
|
|
||||||
|
|
||||||
pos += step;
|
|
||||||
}
|
|
||||||
|
|
||||||
UnlockMutex (soundSource[MUSIC_SOURCE].stream_mutex);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
UnlockMutex (soundSource[MUSIC_SOURCE].stream_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// tells current position of streaming speech
|
// tells current position of streaming speech
|
||||||
int
|
int
|
||||||
GetSoundInfo (int max_len)
|
GetSoundInfo (int max_len)
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ void FastReverse_Page(void);
|
|||||||
void StopTrack(void);
|
void StopTrack(void);
|
||||||
void SpliceTrack(UNICODE *filespec, UNICODE *textspec, UNICODE *TimeStamp, TFB_TrackCB cb);
|
void SpliceTrack(UNICODE *filespec, UNICODE *textspec, UNICODE *TimeStamp, TFB_TrackCB cb);
|
||||||
void SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText);
|
void SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText);
|
||||||
int GetSoundData (void *data);
|
|
||||||
int GetSoundInfo (int max_len);
|
int GetSoundInfo (int max_len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "sis.h"
|
#include "sis.h"
|
||||||
#include "libs/graphics/gfx_common.h"
|
#include "libs/graphics/gfx_common.h"
|
||||||
#include "libs/graphics/drawable.h"
|
#include "libs/graphics/drawable.h"
|
||||||
|
#include "libs/sound/sound.h"
|
||||||
#include "libs/sound/trackplayer.h"
|
#include "libs/sound/trackplayer.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -92,15 +93,15 @@ Oscilloscope (DWORD grab_data)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
TFB_DrawImage_Image (scope_bg, 0, 0, 0, NULL, scope_surf);
|
TFB_DrawImage_Image (scope_bg, 0, 0, 0, NULL, scope_surf);
|
||||||
if (GetSoundData (scope_data))
|
if (GraphForegroundStream (scope_data, RADAR_WIDTH - 2, RADAR_HEIGHT - 2))
|
||||||
{
|
{
|
||||||
int i, r, g, b;
|
int i, r, g, b;
|
||||||
TFB_DrawCanvas_GetPixel (scope_bg->NormalImg,
|
TFB_DrawCanvas_GetPixel (scope_bg->NormalImg,
|
||||||
scope_bg->extent.width / 2, scope_bg->extent.height / 2,
|
scope_bg->extent.width / 2, scope_bg->extent.height / 2,
|
||||||
&r, &g, &b);
|
&r, &g, &b);
|
||||||
for (i = 0; i < RADAR_WIDTH - 3; ++i)
|
for (i = 0; i < RADAR_WIDTH - 3; ++i)
|
||||||
TFB_DrawImage_Line (i + 1, scope_data[i], i + 2,
|
TFB_DrawImage_Line (i + 1, scope_data[i] + 1, i + 2,
|
||||||
scope_data[i + 1], r, g, b, scope_surf);
|
scope_data[i + 1] + 1, r, g, b, scope_surf);
|
||||||
}
|
}
|
||||||
TFB_DrawImage_Image (scope_surf, 0, 0, 0, NULL, scope_frame->image);
|
TFB_DrawImage_Image (scope_surf, 0, 0, 0, NULL, scope_frame->image);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user