Add web build support with custom shell HTML
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
Executable
+74
@@ -0,0 +1,74 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Build spectrogram viewer for the web using Emscripten
|
||||||
|
# Usage: ./build_web.sh [debug|release]
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Get script directory (project root)
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
BUILD_TYPE=${1:-release}
|
||||||
|
RAYLIB_DIR="$SCRIPT_DIR/build/external/raylib-master"
|
||||||
|
SRC_DIR="$SCRIPT_DIR/src"
|
||||||
|
BUILD_DIR="$SCRIPT_DIR/bin/web"
|
||||||
|
RAYLIB_BUILD="$BUILD_DIR/raylib_build"
|
||||||
|
OUTPUT="$BUILD_DIR/rspektrum.html"
|
||||||
|
|
||||||
|
# Create build directories
|
||||||
|
mkdir -p "$BUILD_DIR" "$RAYLIB_BUILD"
|
||||||
|
|
||||||
|
echo "=== Building Spectrogram Viewer for Web ($BUILD_TYPE) ==="
|
||||||
|
echo "Raylib dir: $RAYLIB_DIR"
|
||||||
|
|
||||||
|
# Common compile flags for raylib
|
||||||
|
RAYLIB_CFLAGS="-Os -Wall -DPLATFORM_WEB -DGRAPHICS_API_OPENGL_ES2"
|
||||||
|
if [ "$BUILD_TYPE" = "debug" ]; then
|
||||||
|
RAYLIB_CFLAGS="-g -O0 -Wall -DPLATFORM_WEB -DGRAPHICS_API_OPENGL_ES2"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== Step 1: Compiling raylib for web ==="
|
||||||
|
|
||||||
|
# Compile raylib source files
|
||||||
|
emcc -c "$RAYLIB_DIR/src/rcore.c" $RAYLIB_CFLAGS -o "$RAYLIB_BUILD/rcore.o"
|
||||||
|
emcc -c "$RAYLIB_DIR/src/rshapes.c" $RAYLIB_CFLAGS -o "$RAYLIB_BUILD/rshapes.o"
|
||||||
|
emcc -c "$RAYLIB_DIR/src/rtextures.c" $RAYLIB_CFLAGS -o "$RAYLIB_BUILD/rtextures.o"
|
||||||
|
emcc -c "$RAYLIB_DIR/src/rtext.c" $RAYLIB_CFLAGS -o "$RAYLIB_BUILD/rtext.o"
|
||||||
|
emcc -c "$RAYLIB_DIR/src/rmodels.c" $RAYLIB_CFLAGS -o "$RAYLIB_BUILD/rmodels.o"
|
||||||
|
emcc -c "$RAYLIB_DIR/src/raudio.c" $RAYLIB_CFLAGS -o "$RAYLIB_BUILD/raudio.o"
|
||||||
|
|
||||||
|
# Create static library
|
||||||
|
cd "$RAYLIB_BUILD"
|
||||||
|
emar rcs libraylib.a rcore.o rshapes.o rtextures.o rtext.o rmodels.o raudio.o
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
echo "=== Step 2: Compiling spectrogram for web ==="
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
# Linker flags
|
||||||
|
LDFLAGS="-s USE_GLFW=3 -s ASYNCIFY -s TOTAL_MEMORY=67108864 -s FORCE_FILESYSTEM=1 --preload-file resources@resources --shell-file $SCRIPT_DIR/web_shell.html -s NO_EXIT_RUNTIME=1"
|
||||||
|
|
||||||
|
if [ "$BUILD_TYPE" = "debug" ]; then
|
||||||
|
LDFLAGS="$LDFLAGS -g -O0 -s ASSERTIONS=1"
|
||||||
|
else
|
||||||
|
LDFLAGS="$LDFLAGS -O2"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Compile and link
|
||||||
|
emcc -o "$OUTPUT" \
|
||||||
|
"$SRC_DIR/spectrogram.c" \
|
||||||
|
-I"$RAYLIB_DIR/src" \
|
||||||
|
-I"$RAYLIB_DIR/src/external" \
|
||||||
|
-I"$RAYLIB_DIR/src/external/glfw/include" \
|
||||||
|
-Iinclude \
|
||||||
|
-DPLATFORM_WEB \
|
||||||
|
"$RAYLIB_BUILD/libraylib.a" \
|
||||||
|
$LDFLAGS
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Build complete ==="
|
||||||
|
echo "Output: $OUTPUT"
|
||||||
|
echo ""
|
||||||
|
echo "To test locally, run:"
|
||||||
|
echo " cd $BUILD_DIR && python3 -m http.server 8080"
|
||||||
|
echo "Then open http://localhost:8080/rspektrum.html in your browser"
|
||||||
+184
-51
@@ -96,6 +96,11 @@ typedef struct {
|
|||||||
float freqSelectionStart;
|
float freqSelectionStart;
|
||||||
float freqSelectionEnd;
|
float freqSelectionEnd;
|
||||||
bool isFreqSelecting;
|
bool isFreqSelecting;
|
||||||
|
Vector2 selectStartPos; // For minimum drag distance check
|
||||||
|
bool isDraggingSelection; // Dragging existing selection box
|
||||||
|
Vector2 dragSelectionStartPos; // Mouse position when started dragging selection
|
||||||
|
float dragSelectionTimeStart; // Selection start time when dragging
|
||||||
|
float dragSelectionFreqStart; // Selection freq start when dragging
|
||||||
|
|
||||||
// Viewport/zoom controls
|
// Viewport/zoom controls
|
||||||
float viewStart; // 0-1, start of visible time region
|
float viewStart; // 0-1, start of visible time region
|
||||||
@@ -941,26 +946,66 @@ static void DrawSidebar(void);
|
|||||||
|
|
||||||
static void DrawSelection(Rectangle bounds)
|
static void DrawSelection(Rectangle bounds)
|
||||||
{
|
{
|
||||||
Color overlayColor = Fade(BLACK, 0.5f);
|
// Only draw if selection is not full range AND not currently dragging
|
||||||
float selStartX = bounds.x + app.timeSelectionStart * bounds.width;
|
bool hasSelection = (app.timeSelectionStart > 0.001f || app.timeSelectionEnd < 0.999f ||
|
||||||
float selEndX = bounds.x + app.timeSelectionEnd * bounds.width;
|
app.freqSelectionStart > 0.001f || app.freqSelectionEnd < 0.999f);
|
||||||
|
if (!hasSelection || app.isTimeSelecting) return; // Don't draw overlay while dragging
|
||||||
|
|
||||||
|
Color overlayColor = Fade(BLACK, 0.25f); // Lighter overlay
|
||||||
|
|
||||||
|
// Convert signal coordinates to viewport coordinates
|
||||||
|
float viewWidth = app.viewEnd - app.viewStart;
|
||||||
|
float freqWidth = app.freqViewEnd - app.freqViewStart;
|
||||||
|
|
||||||
|
float selStartX = bounds.x + ((app.timeSelectionStart - app.viewStart) / viewWidth) * bounds.width;
|
||||||
|
float selEndX = bounds.x + ((app.timeSelectionEnd - app.viewStart) / viewWidth) * bounds.width;
|
||||||
|
float selStartY = bounds.y + bounds.height - ((app.freqSelectionEnd - app.freqViewStart) / freqWidth) * bounds.height;
|
||||||
|
float selEndY = bounds.y + bounds.height - ((app.freqSelectionStart - app.freqViewStart) / freqWidth) * bounds.height;
|
||||||
|
|
||||||
|
// Clamp to viewport bounds
|
||||||
|
selStartX = fmaxf(bounds.x, fminf(bounds.x + bounds.width, selStartX));
|
||||||
|
selEndX = fmaxf(bounds.x, fminf(bounds.x + bounds.width, selEndX));
|
||||||
|
selStartY = fmaxf(bounds.y, fminf(bounds.y + bounds.height, selStartY));
|
||||||
|
selEndY = fmaxf(bounds.y, fminf(bounds.y + bounds.height, selEndY));
|
||||||
|
|
||||||
|
// Draw overlay outside the selection box
|
||||||
|
DrawRectangle(bounds.x, bounds.y, selStartX - bounds.x, bounds.height, overlayColor);
|
||||||
|
DrawRectangle(selEndX, bounds.y, bounds.x + bounds.width - selEndX, bounds.height, overlayColor);
|
||||||
|
DrawRectangle(selStartX, bounds.y, selEndX - selStartX, selStartY - bounds.y, overlayColor);
|
||||||
|
DrawRectangle(selStartX, selEndY, selEndX - selStartX, bounds.y + bounds.height - selEndY, overlayColor);
|
||||||
|
|
||||||
|
// Draw selection box border
|
||||||
|
DrawRectangleLinesEx((Rectangle){ selStartX, selStartY, selEndX - selStartX, selEndY - selStartY }, 2, YELLOW);
|
||||||
|
}
|
||||||
|
|
||||||
if (selStartX > bounds.x) DrawRectangle(bounds.x, bounds.y, selStartX - bounds.x, bounds.height, overlayColor);
|
static void DrawSelectionDrag(Rectangle bounds)
|
||||||
if (selEndX < bounds.x + bounds.width) DrawRectangle(selEndX, bounds.y, bounds.x + bounds.width - selEndX, bounds.height, overlayColor);
|
{
|
||||||
|
// Draw bounding box while dragging (no overlay)
|
||||||
float selStartY = bounds.y + bounds.height - app.freqSelectionEnd * bounds.height;
|
if ((!app.isTimeSelecting && !app.isFreqSelecting && !app.isDraggingSelection) ||
|
||||||
float selEndY = bounds.y + bounds.height - app.freqSelectionStart * bounds.height;
|
(app.isDraggingSelection && !IsMouseButtonDown(MOUSE_LEFT_BUTTON))) return;
|
||||||
|
|
||||||
if (selStartY > bounds.y) DrawRectangle(selStartX, bounds.y, selEndX - selStartX, selStartY - bounds.y, overlayColor);
|
// Convert signal coordinates to viewport coordinates
|
||||||
if (selEndY < bounds.y + bounds.height) DrawRectangle(selStartX, selEndY, selEndX - selStartX, bounds.y + bounds.height - selEndY, overlayColor);
|
float viewWidth = app.viewEnd - app.viewStart;
|
||||||
|
float freqWidth = app.freqViewEnd - app.freqViewStart;
|
||||||
DrawLineV((Vector2){ selStartX, bounds.y }, (Vector2){ selStartX, bounds.y + bounds.height }, YELLOW);
|
|
||||||
DrawLineV((Vector2){ selEndX, bounds.y }, (Vector2){ selEndX, bounds.y + bounds.height }, YELLOW);
|
float selStartX = bounds.x + ((app.timeSelectionStart - app.viewStart) / viewWidth) * bounds.width;
|
||||||
|
float selEndX = bounds.x + ((app.timeSelectionEnd - app.viewStart) / viewWidth) * bounds.width;
|
||||||
if (app.freqSelectionStart > 0.0f || app.freqSelectionEnd < 1.0f) {
|
float selStartY = bounds.y + bounds.height - ((app.freqSelectionEnd - app.freqViewStart) / freqWidth) * bounds.height;
|
||||||
DrawLineV((Vector2){ selStartX, selStartY }, (Vector2){ selEndX, selStartY }, CYAN);
|
float selEndY = bounds.y + bounds.height - ((app.freqSelectionStart - app.freqViewStart) / freqWidth) * bounds.height;
|
||||||
DrawLineV((Vector2){ selStartX, selEndY }, (Vector2){ selEndX, selEndY }, CYAN);
|
|
||||||
}
|
// Clamp to viewport bounds
|
||||||
|
selStartX = fmaxf(bounds.x, fminf(bounds.x + bounds.width, selStartX));
|
||||||
|
selEndX = fmaxf(bounds.x, fminf(bounds.x + bounds.width, selEndX));
|
||||||
|
selStartY = fmaxf(bounds.y, fminf(bounds.y + bounds.height, selStartY));
|
||||||
|
selEndY = fmaxf(bounds.y, fminf(bounds.y + bounds.height, selEndY));
|
||||||
|
|
||||||
|
// Normalize coordinates for drawing
|
||||||
|
float x = selStartX < selEndX ? selStartX : selEndX;
|
||||||
|
float w = fabsf(selEndX - selStartX);
|
||||||
|
float y = selStartY < selEndY ? selStartY : selEndY;
|
||||||
|
float h = fabsf(selEndY - selStartY);
|
||||||
|
|
||||||
|
DrawRectangleLinesEx((Rectangle){ x, y, w, h }, 2, YELLOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DrawSidebar(void)
|
static void DrawSidebar(void)
|
||||||
@@ -1139,7 +1184,7 @@ static bool UpdateSlider(Rectangle bounds, float* value)
|
|||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
SetConfigFlags(FLAG_VSYNC_HINT | FLAG_WINDOW_HIGHDPI);
|
SetConfigFlags(FLAG_VSYNC_HINT);
|
||||||
InitWindow(1280, 800, "Spectrogram Viewer");
|
InitWindow(1280, 800, "Spectrogram Viewer");
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
SetTraceLogLevel(LOG_WARNING); // Suppress INFO texture logs
|
SetTraceLogLevel(LOG_WARNING); // Suppress INFO texture logs
|
||||||
@@ -1227,6 +1272,11 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle window resize
|
||||||
|
if (IsWindowResized()) {
|
||||||
|
app.visibleTextureValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
// View controls
|
// View controls
|
||||||
if (app.loaded && !app.showFileBrowser) {
|
if (app.loaded && !app.showFileBrowser) {
|
||||||
// Spectrogram area fills remaining window space
|
// Spectrogram area fills remaining window space
|
||||||
@@ -1357,7 +1407,7 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Selection (only when mouse is in spectrogram area, not sidebar)
|
// Selection: box select with LMB drag, right-click to clear
|
||||||
float selSidebarWidth = 320;
|
float selSidebarWidth = 320;
|
||||||
float selLabelHeight = 15;
|
float selLabelHeight = 15;
|
||||||
float selScrollbarHeight = 18;
|
float selScrollbarHeight = 18;
|
||||||
@@ -1374,46 +1424,128 @@ int main(int argc, char* argv[])
|
|||||||
};
|
};
|
||||||
Vector2 mousePos = GetMousePosition();
|
Vector2 mousePos = GetMousePosition();
|
||||||
|
|
||||||
if (app.loaded && !app.showFileBrowser && mousePos.x > 385 && CheckCollisionPointRec(mousePos, selBounds)) {
|
// Right-click clears selection
|
||||||
bool shiftHeld = IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT);
|
if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT) && CheckCollisionPointRec(mousePos, selBounds)) {
|
||||||
|
app.timeSelectionStart = 0.0f;
|
||||||
|
app.timeSelectionEnd = 1.0f;
|
||||||
|
app.freqSelectionStart = 0.0f;
|
||||||
|
app.freqSelectionEnd = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) && !app.isPanning) {
|
// Check if click is inside existing selection (for dragging)
|
||||||
if (shiftHeld) {
|
bool hasSelection = (app.timeSelectionStart > 0.001f || app.timeSelectionEnd < 0.999f ||
|
||||||
app.isFreqSelecting = true;
|
app.freqSelectionStart > 0.001f || app.freqSelectionEnd < 0.999f);
|
||||||
float t = 1.0f - (mousePos.y - selBounds.y) / selBounds.height;
|
bool clickInsideSelection = false;
|
||||||
app.freqSelectionStart = Clamp(t, 0.0f, 1.0f);
|
bool hoverInsideSelection = false;
|
||||||
app.freqSelectionEnd = app.freqSelectionStart;
|
if (hasSelection && CheckCollisionPointRec(mousePos, selBounds)) {
|
||||||
} else if (!IsKeyDown(KEY_LEFT_ALT) && !IsKeyDown(KEY_RIGHT_ALT)) {
|
// Convert mouse position to signal coordinates
|
||||||
app.isTimeSelecting = true;
|
float viewWidth = app.viewEnd - app.viewStart;
|
||||||
app.timeSelectionStart = Clamp((mousePos.x - selBounds.x) / selBounds.width, 0.0f, 1.0f);
|
float freqWidth = app.freqViewEnd - app.freqViewStart;
|
||||||
app.timeSelectionEnd = app.timeSelectionStart;
|
float mouseTime = app.viewStart + ((mousePos.x - selBounds.x) / selBounds.width) * viewWidth;
|
||||||
|
float mouseFreq = app.freqViewStart + (1.0f - (mousePos.y - selBounds.y) / selBounds.height) * freqWidth;
|
||||||
|
|
||||||
|
if (mouseTime >= app.timeSelectionStart && mouseTime <= app.timeSelectionEnd &&
|
||||||
|
mouseFreq >= app.freqSelectionStart && mouseFreq <= app.freqSelectionEnd) {
|
||||||
|
hoverInsideSelection = true;
|
||||||
|
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
|
||||||
|
clickInsideSelection = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set cursor based on context
|
||||||
|
if (app.isDraggingSelection) {
|
||||||
|
SetMouseCursor(MOUSE_CURSOR_RESIZE_ALL); // 4-way arrow while dragging
|
||||||
|
} else if (hoverInsideSelection) {
|
||||||
|
SetMouseCursor(MOUSE_CURSOR_POINTING_HAND); // Pointing hand on hover
|
||||||
|
} else {
|
||||||
|
SetMouseCursor(MOUSE_CURSOR_DEFAULT); // Normal arrow
|
||||||
|
}
|
||||||
|
|
||||||
if (app.isTimeSelecting && IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
|
// LMB drag = box select (time + frequency) OR drag existing selection
|
||||||
app.timeSelectionEnd = Clamp((mousePos.x - selBounds.x) / selBounds.width, 0.0f, 1.0f);
|
if (app.loaded && !app.showFileBrowser && CheckCollisionPointRec(mousePos, selBounds)) {
|
||||||
|
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
|
||||||
|
if (clickInsideSelection) {
|
||||||
|
// Start dragging existing selection
|
||||||
|
app.isDraggingSelection = true;
|
||||||
|
app.dragSelectionStartPos = mousePos;
|
||||||
|
app.dragSelectionTimeStart = app.timeSelectionStart;
|
||||||
|
app.dragSelectionFreqStart = app.freqSelectionStart;
|
||||||
|
} else {
|
||||||
|
// Start new box selection
|
||||||
|
app.isTimeSelecting = true;
|
||||||
|
app.isFreqSelecting = true;
|
||||||
|
app.selectStartPos = mousePos;
|
||||||
|
|
||||||
|
// Convert screen position to signal coordinates (accounting for zoom)
|
||||||
|
float viewportT = (mousePos.x - selBounds.x) / selBounds.width;
|
||||||
|
float viewportF = 1.0f - (mousePos.y - selBounds.y) / selBounds.height;
|
||||||
|
|
||||||
|
app.timeSelectionStart = Clamp(app.viewStart + viewportT * (app.viewEnd - app.viewStart), 0.0f, 1.0f);
|
||||||
|
app.timeSelectionEnd = app.timeSelectionStart;
|
||||||
|
app.freqSelectionStart = Clamp(app.freqViewStart + viewportF * (app.freqViewEnd - app.freqViewStart), 0.0f, 1.0f);
|
||||||
|
app.freqSelectionEnd = app.freqSelectionStart;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (app.isFreqSelecting && IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
|
|
||||||
float t = 1.0f - (mousePos.y - selBounds.y) / selBounds.height;
|
// Dragging existing selection
|
||||||
app.freqSelectionEnd = Clamp(t, 0.0f, 1.0f);
|
if (app.isDraggingSelection && IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
|
||||||
|
float viewWidth = app.viewEnd - app.viewStart;
|
||||||
|
float freqWidth = app.freqViewEnd - app.freqViewStart;
|
||||||
|
|
||||||
|
float dx = (mousePos.x - app.dragSelectionStartPos.x) / selBounds.width;
|
||||||
|
float dy = (mousePos.y - app.dragSelectionStartPos.y) / selBounds.height;
|
||||||
|
|
||||||
|
float timeShift = dx * viewWidth;
|
||||||
|
float freqShift = -dy * freqWidth; // Y is inverted
|
||||||
|
|
||||||
|
float timeWidth = app.timeSelectionEnd - app.timeSelectionStart;
|
||||||
|
float freqHeight = app.freqSelectionEnd - app.freqSelectionStart;
|
||||||
|
|
||||||
|
app.timeSelectionStart = Clamp(app.dragSelectionTimeStart + timeShift, 0.0f, 1.0f - timeWidth);
|
||||||
|
app.timeSelectionEnd = app.timeSelectionStart + timeWidth;
|
||||||
|
app.freqSelectionStart = Clamp(app.dragSelectionFreqStart + freqShift, 0.0f, 1.0f - freqHeight);
|
||||||
|
app.freqSelectionEnd = app.freqSelectionStart + freqHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creating new box selection
|
||||||
|
if ((app.isTimeSelecting || app.isFreqSelecting) && IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
|
||||||
|
float viewportT = (mousePos.x - selBounds.x) / selBounds.width;
|
||||||
|
float viewportF = 1.0f - (mousePos.y - selBounds.y) / selBounds.height;
|
||||||
|
|
||||||
|
app.timeSelectionEnd = Clamp(app.viewStart + viewportT * (app.viewEnd - app.viewStart), 0.0f, 1.0f);
|
||||||
|
app.freqSelectionEnd = Clamp(app.freqViewStart + viewportF * (app.freqViewEnd - app.freqViewStart), 0.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) {
|
if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) {
|
||||||
if (app.isTimeSelecting) {
|
if (app.isDraggingSelection) {
|
||||||
|
app.isDraggingSelection = false;
|
||||||
|
} else if (app.isTimeSelecting || app.isFreqSelecting) {
|
||||||
|
// Check if drag was large enough (minimum 5 pixels)
|
||||||
|
float dx = mousePos.x - app.selectStartPos.x;
|
||||||
|
float dy = mousePos.y - app.selectStartPos.y;
|
||||||
|
float dragDist = sqrtf(dx * dx + dy * dy);
|
||||||
|
if (dragDist > 5.0f) {
|
||||||
|
// Normalize so start < end
|
||||||
|
if (app.timeSelectionEnd < app.timeSelectionStart) {
|
||||||
|
float tmp = app.timeSelectionStart;
|
||||||
|
app.timeSelectionStart = app.timeSelectionEnd;
|
||||||
|
app.timeSelectionEnd = tmp;
|
||||||
|
}
|
||||||
|
if (app.freqSelectionEnd < app.freqSelectionStart) {
|
||||||
|
float tmp = app.freqSelectionStart;
|
||||||
|
app.freqSelectionStart = app.freqSelectionEnd;
|
||||||
|
app.freqSelectionEnd = tmp;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Drag too small - revert to full range
|
||||||
|
app.timeSelectionStart = 0.0f;
|
||||||
|
app.timeSelectionEnd = 1.0f;
|
||||||
|
app.freqSelectionStart = 0.0f;
|
||||||
|
app.freqSelectionEnd = 1.0f;
|
||||||
|
}
|
||||||
app.isTimeSelecting = false;
|
app.isTimeSelecting = false;
|
||||||
if (app.timeSelectionEnd < app.timeSelectionStart) {
|
|
||||||
float tmp = app.timeSelectionStart;
|
|
||||||
app.timeSelectionStart = app.timeSelectionEnd;
|
|
||||||
app.timeSelectionEnd = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (app.isFreqSelecting) {
|
|
||||||
app.isFreqSelecting = false;
|
app.isFreqSelecting = false;
|
||||||
if (app.freqSelectionEnd < app.freqSelectionStart) {
|
|
||||||
float tmp = app.freqSelectionStart;
|
|
||||||
app.freqSelectionStart = app.freqSelectionEnd;
|
|
||||||
app.freqSelectionEnd = tmp;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1566,6 +1698,7 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
if (app.showGrid) DrawSpectrogramGrid(viewBounds, 10, 8, Fade(GRAY, 0.3f));
|
if (app.showGrid) DrawSpectrogramGrid(viewBounds, 10, 8, Fade(GRAY, 0.3f));
|
||||||
DrawSelection(viewBounds);
|
DrawSelection(viewBounds);
|
||||||
|
DrawSelectionDrag(viewBounds);
|
||||||
DrawLabels(viewBounds);
|
DrawLabels(viewBounds);
|
||||||
float maxFreq = (float)app.signal.sampleRate / 2.0f;
|
float maxFreq = (float)app.signal.sampleRate / 2.0f;
|
||||||
float freqMin = app.freqViewStart * maxFreq;
|
float freqMin = app.freqViewStart * maxFreq;
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
<title>Spectrogram Viewer</title>
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #1e1e1e;
|
||||||
|
}
|
||||||
|
canvas.emscripten {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
display: block;
|
||||||
|
border: 0px none;
|
||||||
|
outline: none;
|
||||||
|
background-color: #1e1e1e;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex="-1"></canvas>
|
||||||
|
<p id="output" />
|
||||||
|
<script>
|
||||||
|
var Module = {
|
||||||
|
print: (function() {
|
||||||
|
var element = document.getElementById('output');
|
||||||
|
if (element) element.value = '';
|
||||||
|
return function(text) {
|
||||||
|
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
|
||||||
|
console.log(text);
|
||||||
|
if (element) {
|
||||||
|
element.value += text + "\n";
|
||||||
|
element.scrollTop = element.scrollHeight;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(),
|
||||||
|
canvas: (function() {
|
||||||
|
var canvas = document.getElementById('canvas');
|
||||||
|
return canvas;
|
||||||
|
})()
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
{{{ SCRIPT }}}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user