455 lines
8.8 KiB
C
455 lines
8.8 KiB
C
#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__))
|
|
# define _WIN32
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
#ifdef _WIN32
|
|
#include <GL/glew.h>
|
|
#endif
|
|
#include <GLFW/glfw3.h>
|
|
|
|
#include "fosphor.h"
|
|
#include "private.h"
|
|
|
|
struct app_state
|
|
{
|
|
struct fosphor *fosphor;
|
|
struct fosphor_render render_main;
|
|
struct fosphor_render render_zoom;
|
|
|
|
FILE *src_fh;
|
|
void *src_buf;
|
|
|
|
int w, h;
|
|
|
|
int db_ref, db_per_div_idx;
|
|
float ratio;
|
|
double zoom_width, zoom_center;
|
|
int zoom_enable;
|
|
};
|
|
|
|
static struct app_state _g_as, *g_as = &_g_as;
|
|
|
|
static const int k_db_per_div[] = { 1, 2, 5, 10, 20 };
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Timing utils */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
#if defined(_WIN32) && !defined(__MINGW32__)
|
|
|
|
#include <time.h>
|
|
#include <windows.h>
|
|
|
|
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
|
|
# define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
|
|
#else
|
|
# define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
|
|
#endif
|
|
|
|
struct timezone
|
|
{
|
|
int tz_minuteswest; /* minutes W of Greenwich */
|
|
int tz_dsttime; /* type of dst correction */
|
|
};
|
|
|
|
static int
|
|
gettimeofday(struct timeval *tv, struct timezone *tz)
|
|
{
|
|
FILETIME ft;
|
|
unsigned __int64 tmpres = 0;
|
|
static int tzflag;
|
|
|
|
if (NULL != tv)
|
|
{
|
|
GetSystemTimeAsFileTime(&ft);
|
|
|
|
tmpres |= ft.dwHighDateTime;
|
|
tmpres <<= 32;
|
|
tmpres |= ft.dwLowDateTime;
|
|
|
|
/*converting file time to unix epoch*/
|
|
tmpres -= DELTA_EPOCH_IN_MICROSECS;
|
|
tmpres /= 10; /*convert into microseconds*/
|
|
tv->tv_sec = (long)(tmpres / 1000000UL);
|
|
tv->tv_usec = (long)(tmpres % 1000000UL);
|
|
}
|
|
|
|
if (NULL != tz)
|
|
{
|
|
if (!tzflag)
|
|
{
|
|
_tzset();
|
|
tzflag++;
|
|
}
|
|
tz->tz_minuteswest = _timezone / 60;
|
|
tz->tz_dsttime = _daylight;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#else /* _WIN32 */
|
|
# include <sys/time.h>
|
|
#endif /* _WIN32 */
|
|
|
|
|
|
uint64_t
|
|
time_now(void)
|
|
{
|
|
struct timeval tv;
|
|
gettimeofday(&tv, NULL);
|
|
return (tv.tv_sec * 1000000UL) + tv.tv_usec;
|
|
}
|
|
|
|
static uint64_t tic;
|
|
|
|
void
|
|
time_tic(void)
|
|
{
|
|
tic = time_now();
|
|
}
|
|
|
|
uint64_t
|
|
time_toc(const char *str)
|
|
{
|
|
uint64_t d = time_now() - tic;
|
|
printf("%s: %d us\n", str, (int)d);
|
|
return d;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* GLFW */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
#define BATCH_LEN 128
|
|
#define BATCH_COUNT 4
|
|
|
|
static void
|
|
glfw_render(GLFWwindow *wnd)
|
|
{
|
|
static int fc = 0;
|
|
int c, r, o;
|
|
|
|
/* Timing */
|
|
if (!fc)
|
|
time_tic();
|
|
if (fc == 99) {
|
|
uint64_t t;
|
|
float bw;
|
|
|
|
t = time_toc("100 Frames time");
|
|
|
|
bw = (1e6f * FOSPHOR_FFT_LEN * BATCH_LEN * BATCH_COUNT) / ((float)t / 100.0f);
|
|
fprintf(stderr, "BW estimated: %f Msps\n", bw / 1e6);
|
|
}
|
|
|
|
fc = (fc+1) % 100;
|
|
|
|
/* Clear everything */
|
|
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
/* Process some samples */
|
|
for (c=0; c<BATCH_COUNT; c++) {
|
|
r = sizeof(float) * 2 * FOSPHOR_FFT_LEN * BATCH_LEN;
|
|
o = 0;
|
|
|
|
while (r) {
|
|
int rc;
|
|
|
|
rc = fread((char*)g_as->src_buf + o, 1, r, g_as->src_fh);
|
|
if (rc <= 0) {
|
|
if (fseek(g_as->src_fh, 0, SEEK_SET))
|
|
abort();
|
|
continue;
|
|
}
|
|
|
|
r -= rc;
|
|
o += rc;
|
|
}
|
|
|
|
fosphor_process(g_as->fosphor, g_as->src_buf, FOSPHOR_FFT_LEN * BATCH_LEN);
|
|
}
|
|
|
|
/* Draw fosphor */
|
|
fosphor_draw(g_as->fosphor, &g_as->render_main);
|
|
|
|
if (g_as->zoom_enable)
|
|
fosphor_draw(g_as->fosphor, &g_as->render_zoom);
|
|
|
|
/* Done, swap buffer */
|
|
glfwSwapBuffers(wnd);
|
|
}
|
|
|
|
static void
|
|
_update_fosphor(void)
|
|
{
|
|
/* Configure the screen zones */
|
|
if (g_as->zoom_enable)
|
|
{
|
|
int a = (int)(g_as->w * 0.65f);
|
|
|
|
g_as->render_main.width = a;
|
|
g_as->render_main.height = g_as->h;
|
|
g_as->render_main.options &= ~FRO_COLOR_SCALE;
|
|
|
|
g_as->render_zoom.pos_x = a - 10;
|
|
g_as->render_zoom.width = g_as->w - a + 10;
|
|
g_as->render_zoom.height = g_as->h;
|
|
}
|
|
else
|
|
{
|
|
g_as->render_main.width = g_as->w;
|
|
g_as->render_main.height = g_as->h;
|
|
g_as->render_main.options |= FRO_COLOR_SCALE;
|
|
}
|
|
|
|
g_as->render_main.histo_wf_ratio = g_as->ratio;
|
|
g_as->render_zoom.histo_wf_ratio = g_as->ratio;
|
|
|
|
/* Only render channels when there is a zoom */
|
|
if (g_as->zoom_enable)
|
|
g_as->render_main.options |= FRO_CHANNELS;
|
|
else
|
|
g_as->render_main.options &= ~FRO_CHANNELS;
|
|
|
|
/* Set the zoom */
|
|
g_as->render_main.channels[0].enabled = g_as->zoom_enable;
|
|
g_as->render_main.channels[0].center = (float)g_as->zoom_center;
|
|
g_as->render_main.channels[0].width = (float)g_as->zoom_width;
|
|
|
|
g_as->render_zoom.freq_center = g_as->zoom_center;
|
|
g_as->render_zoom.freq_span = g_as->zoom_width;
|
|
|
|
/* Update render options */
|
|
fosphor_render_refresh(&g_as->render_main);
|
|
fosphor_render_refresh(&g_as->render_zoom);
|
|
|
|
/* Set other fosphor params */
|
|
if (g_as->fosphor) {
|
|
fosphor_set_power_range(g_as->fosphor, g_as->db_ref, k_db_per_div[g_as->db_per_div_idx]);
|
|
}
|
|
}
|
|
|
|
static void
|
|
glfw_cb_reshape(GLFWwindow *wnd, int w, int h)
|
|
{
|
|
if (w < 0 || h < 0)
|
|
glfwGetFramebufferSize(wnd, &w, &h);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
glOrtho(0.0, (double)w, 0.0, (double)h, -1.0, 1.0);
|
|
|
|
glViewport(0, 0, w, h);
|
|
|
|
g_as->w = w;
|
|
g_as->h = h;
|
|
|
|
_update_fosphor();
|
|
}
|
|
|
|
static void
|
|
glfw_cb_key(GLFWwindow *wnd, int key, int scancode, int action, int mods)
|
|
{
|
|
if (action != GLFW_PRESS && action != GLFW_REPEAT)
|
|
return;
|
|
|
|
switch (key)
|
|
{
|
|
case GLFW_KEY_ESCAPE:
|
|
exit(0);
|
|
break;
|
|
|
|
case GLFW_KEY_UP:
|
|
g_as->db_ref -= k_db_per_div[g_as->db_per_div_idx];
|
|
break;
|
|
|
|
case GLFW_KEY_DOWN:
|
|
g_as->db_ref += k_db_per_div[g_as->db_per_div_idx];
|
|
break;
|
|
|
|
case GLFW_KEY_LEFT:
|
|
if (g_as->db_per_div_idx > 0)
|
|
g_as->db_per_div_idx--;
|
|
break;
|
|
|
|
case GLFW_KEY_RIGHT:
|
|
if (g_as->db_per_div_idx < 4)
|
|
g_as->db_per_div_idx++;
|
|
break;
|
|
|
|
case GLFW_KEY_W:
|
|
g_as->zoom_width *= 2.0;
|
|
break;
|
|
|
|
case GLFW_KEY_S:
|
|
g_as->zoom_width /= 2.0;
|
|
break;
|
|
|
|
case GLFW_KEY_A:
|
|
g_as->zoom_center -= g_as->zoom_width / 8.0;
|
|
break;
|
|
|
|
case GLFW_KEY_D:
|
|
g_as->zoom_center += g_as->zoom_width / 8.0;
|
|
break;
|
|
|
|
case GLFW_KEY_Z:
|
|
g_as->zoom_enable ^= 1;
|
|
break;
|
|
|
|
case GLFW_KEY_Q:
|
|
if (g_as->ratio < 0.8f)
|
|
g_as->ratio += 0.1f;
|
|
break;
|
|
|
|
case GLFW_KEY_E:
|
|
if (g_as->ratio > 0.2f)
|
|
g_as->ratio -= 0.1f;
|
|
break;
|
|
}
|
|
|
|
_update_fosphor();
|
|
}
|
|
|
|
static GLFWwindow *
|
|
glfw_init(void)
|
|
{
|
|
GLFWwindow *wnd;
|
|
|
|
/* Main glfw init */
|
|
glfwInit();
|
|
|
|
/* Window init */
|
|
wnd = glfwCreateWindow(1024, 1024, "Fosphor test", NULL, NULL);
|
|
if (!wnd)
|
|
return NULL;
|
|
|
|
glfwMakeContextCurrent(wnd);
|
|
|
|
#ifdef _WIN32
|
|
/* Init GLEW (on win32) */
|
|
glewInit();
|
|
#endif
|
|
|
|
/* Disable VSync to test speed */
|
|
glfwSwapInterval(0);
|
|
|
|
/* Callbacks */
|
|
glfwSetFramebufferSizeCallback(wnd, glfw_cb_reshape);
|
|
glfwSetKeyCallback(wnd, glfw_cb_key);
|
|
|
|
/* Force inital window size config */
|
|
glfw_cb_reshape(wnd, -1, -1);
|
|
|
|
return wnd;
|
|
}
|
|
|
|
static void
|
|
glfw_cleanup(GLFWwindow *wnd)
|
|
{
|
|
glfwDestroyWindow(wnd);
|
|
glfwTerminate();
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Main */
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
GLFWwindow *wnd = NULL;
|
|
int rv;
|
|
|
|
/* Open source file */
|
|
if (argc == 2) {
|
|
g_as->src_fh = fopen(argv[1], "rb");
|
|
if (!g_as->src_fh) {
|
|
fprintf(stderr, "[!] Failed to open input file\n");
|
|
return -EIO;
|
|
}
|
|
} else if (argc == 1) {
|
|
g_as->src_fh = stdin;
|
|
} else {
|
|
fprintf(stderr, "Usage: %s filename.cfile\n", argv[0]);
|
|
return -EINVAL;;
|
|
}
|
|
|
|
g_as->src_buf = malloc(2 * sizeof(float) * FOSPHOR_FFT_LEN * FOSPHOR_FFT_MAX_BATCH);
|
|
if (!g_as->src_buf) {
|
|
rv = -ENOMEM;
|
|
goto error;
|
|
}
|
|
|
|
/* Init our state */
|
|
g_as->db_per_div_idx = 3;
|
|
g_as->db_ref = 0;
|
|
g_as->ratio = 0.5f;
|
|
g_as->zoom_center = 0.5;
|
|
g_as->zoom_width = 0.2;
|
|
|
|
/* Default fosphor render options */
|
|
fosphor_render_defaults(&g_as->render_main);
|
|
fosphor_render_defaults(&g_as->render_zoom);
|
|
g_as->render_zoom.options &= ~(FRO_LABEL_PWR | FRO_LABEL_TIME);
|
|
|
|
g_as->render_main.histo_wf_ratio = 0.35f;
|
|
g_as->render_zoom.histo_wf_ratio = 0.35f;
|
|
|
|
/* Init GLFW */
|
|
wnd = glfw_init();
|
|
if (!wnd) {
|
|
fprintf(stderr, "[!] Failed to initialize GLFW window\n");
|
|
rv = -EIO;
|
|
goto error;
|
|
}
|
|
|
|
/* Init fosphor */
|
|
g_as->fosphor = fosphor_init();
|
|
if (!g_as->fosphor) {
|
|
fprintf(stderr, "[!] Failed to initialize fosphor\n");
|
|
rv = -EIO;
|
|
goto error;
|
|
}
|
|
|
|
fosphor_set_power_range(g_as->fosphor, g_as->db_ref, k_db_per_div[g_as->db_per_div_idx]);
|
|
|
|
/* Run ! */
|
|
while (!glfwWindowShouldClose(wnd))
|
|
{
|
|
glfw_render(wnd);
|
|
glfwPollEvents();
|
|
}
|
|
|
|
rv = 0;
|
|
|
|
/* Cleanup */
|
|
error:
|
|
if (g_as->fosphor)
|
|
fosphor_release(g_as->fosphor);
|
|
|
|
if (wnd)
|
|
glfw_cleanup(wnd);
|
|
|
|
free(g_as->src_buf);
|
|
fclose(g_as->src_fh);
|
|
|
|
return rv;
|
|
}
|