From e940f8b3b60c33cedbe26c8906eb6d9f0066e40f Mon Sep 17 00:00:00 2001 From: Ahmet Inan Date: Mon, 2 Feb 2015 00:04:40 +0100 Subject: [PATCH] added PD180 support and made image size more flexible --- app/src/main/java/xdsopl/robot36/Decoder.java | 49 +++++++++-------- .../main/java/xdsopl/robot36/ImageView.java | 28 +++++++--- .../java/xdsopl/robot36/MainActivity.java | 3 ++ app/src/main/res/menu/menu_main.xml | 2 + app/src/main/res/values/strings.xml | 1 + app/src/main/rs/calibration_detector.rsh | 2 + app/src/main/rs/constants.rsh | 3 ++ app/src/main/rs/decoder.rs | 40 ++++++++++++-- app/src/main/rs/initialization.rsh | 1 + app/src/main/rs/modes.rsh | 52 +++++++++++++++++++ app/src/main/rs/scanline_estimator.rsh | 18 ++++--- app/src/main/rs/state.rsh | 3 ++ 12 files changed, 162 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/xdsopl/robot36/Decoder.java b/app/src/main/java/xdsopl/robot36/Decoder.java index 6c45fbc..ee9b52c 100644 --- a/app/src/main/java/xdsopl/robot36/Decoder.java +++ b/app/src/main/java/xdsopl/robot36/Decoder.java @@ -37,6 +37,8 @@ public class Decoder { private final int channelConfig = AudioFormat.CHANNEL_IN_MONO; private final int audioFormat = AudioFormat.ENCODING_PCM_16BIT; private final int sampleRate = 44100; + private final int maxHeight = freeRunReserve(496); + private final int maxWidth = 640; private final short[] audioBuffer; private final int[] pixelBuffer; private final int[] spectrumBuffer; @@ -70,6 +72,7 @@ public class Decoder { private final int mode_scottie2 = 6; private final int mode_scottieDX = 7; private final int mode_wrasseSC2_180 = 8; + private final int mode_pd180 = 9; private final Thread thread = new Thread() { @Override @@ -80,7 +83,7 @@ public class Decoder { return; if (drawImage) { image.drawCanvas(); - if(enableAnalyzer) { + if (enableAnalyzer) { spectrum.drawCanvas(); spectrogram.drawCanvas(); meter.drawCanvas(); @@ -98,7 +101,7 @@ public class Decoder { this.spectrum = spectrum; this.meter = meter; this.activity = activity; - pixelBuffer = new int[image.bitmap.getWidth() * image.bitmap.getHeight()]; + pixelBuffer = new int[maxWidth * maxHeight]; spectrumBuffer = new int[spectrum.bitmap.getWidth() * spectrum.bitmap.getHeight()]; spectrogramBuffer = new int[spectrogram.bitmap.getWidth() * spectrogram.bitmap.getHeight()]; @@ -142,8 +145,7 @@ public class Decoder { rsDecoder.bind_saved_height(rsDecoderSavedHeight); rsDecoder.bind_volume(rsDecoderVolume); rsDecoder.bind_saved_buffer(rsDecoderSavedBuffer); - rsDecoder.invoke_initialize(sampleRate, valueBufferLength, - image.bitmap.getWidth(), image.bitmap.getHeight(), + rsDecoder.invoke_initialize(sampleRate, valueBufferLength, maxWidth, maxHeight, spectrum.bitmap.getWidth(), spectrum.bitmap.getHeight(), spectrogram.bitmap.getWidth(), spectrogram.bitmap.getHeight()); @@ -166,8 +168,9 @@ public class Decoder { void scottie2_mode() { rsDecoder.invoke_scottie2_mode(); } void scottieDX_mode() { rsDecoder.invoke_scottieDX_mode(); } void wrasseSC2_180_mode() { rsDecoder.invoke_wrasseSC2_180_mode(); } + void pd180_mode() { rsDecoder.invoke_pd180_mode(); } - + int freeRunReserve(int height) { return (height * 3) / 2; } void increaseUpdateRate() { updateRate = Math.min(4, updateRate + 1); } void decreaseUpdateRate() { updateRate = Math.max(0, updateRate - 1); } void updateTitle(int id) { activity.updateTitle(activity.getString(id)); } @@ -176,50 +179,45 @@ public class Decoder { { switch (mode) { case mode_raw: - image.imageWidth = image.bitmap.getWidth(); - image.imageHeight = image.bitmap.getHeight(); + image.setImageResolution(maxWidth, maxHeight); updateTitle(R.string.action_raw_mode); break; case mode_robot36: - image.imageWidth = 320; - image.imageHeight = 240; + image.setImageResolution(320, freeRunReserve(240)); updateTitle(R.string.action_robot36_mode); break; case mode_robot72: - image.imageWidth = 320; - image.imageHeight = 240; + image.setImageResolution(320, freeRunReserve(240)); updateTitle(R.string.action_robot72_mode); break; case mode_martin1: - image.imageWidth = 320; - image.imageHeight = 256; + image.setImageResolution(320, freeRunReserve(256)); updateTitle(R.string.action_martin1_mode); break; case mode_martin2: - image.imageWidth = 320; - image.imageHeight = 256; + image.setImageResolution(320, freeRunReserve(256)); updateTitle(R.string.action_martin2_mode); break; case mode_scottie1: - image.imageWidth = 320; - image.imageHeight = 256; + image.setImageResolution(320, freeRunReserve(256)); updateTitle(R.string.action_scottie1_mode); break; case mode_scottie2: - image.imageWidth = 320; - image.imageHeight = 256; + image.setImageResolution(320, freeRunReserve(256)); updateTitle(R.string.action_scottie2_mode); break; case mode_scottieDX: - image.imageWidth = 320; - image.imageHeight = 256; + image.setImageResolution(320, freeRunReserve(256)); updateTitle(R.string.action_scottieDX_mode); break; case mode_wrasseSC2_180: - image.imageWidth = 320; - image.imageHeight = 256; + image.setImageResolution(320, freeRunReserve(256)); updateTitle(R.string.action_wrasseSC2_180_mode); break; + case mode_pd180: + image.setImageResolution(640, freeRunReserve(496)); + updateTitle(R.string.action_pd180_mode); + break; default: break; } @@ -256,12 +254,13 @@ public class Decoder { rsDecoderAudioBuffer.copyFrom(audioBuffer); rsDecoder.invoke_decode(samples); - rsDecoderPixelBuffer.copyTo(pixelBuffer); - image.bitmap.setPixels(pixelBuffer, 0, image.bitmap.getWidth(), 0, 0, image.bitmap.getWidth(), image.bitmap.getHeight()); rsDecoderCurrentMode.copyTo(currentMode); switch_mode(currentMode[0]); + rsDecoderPixelBuffer.copyTo(pixelBuffer); + image.setPixels(pixelBuffer); + rsDecoderVolume.copyTo(volume); meter.volume = volume[0]; diff --git a/app/src/main/java/xdsopl/robot36/ImageView.java b/app/src/main/java/xdsopl/robot36/ImageView.java index 0412291..ac72a43 100644 --- a/app/src/main/java/xdsopl/robot36/ImageView.java +++ b/app/src/main/java/xdsopl/robot36/ImageView.java @@ -29,20 +29,36 @@ import android.graphics.Paint; public class ImageView extends SurfaceView implements SurfaceHolder.Callback { private int canvasWidth = -1, canvasHeight = -1; private boolean cantTouchThis = true; - public int imageWidth = 320; - public int imageHeight = 240; + private int imageWidth = -1; + private int imageHeight = -1; public boolean intScale = false; private final SurfaceHolder holder; - public final Bitmap bitmap; + public Bitmap bitmap = null; private final Paint paint; public ImageView(Context context, AttributeSet attrs) { super(context, attrs); holder = getHolder(); holder.addCallback(this); - paint = new Paint(Paint.FILTER_BITMAP_FLAG); - bitmap = Bitmap.createBitmap(320, 384, Bitmap.Config.ARGB_8888); + } + + public void setImageResolution(int width, int height) { + synchronized (holder) { + if (width != imageWidth || height != imageHeight) { + imageWidth = width; + imageHeight = height; + if (bitmap != null) + bitmap.recycle(); + bitmap = Bitmap.createBitmap(imageWidth, imageHeight, Bitmap.Config.ARGB_8888); + } + } + } + + public void setPixels(int pixels[]) { + synchronized (holder) { + bitmap.setPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight()); + } } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { @@ -67,7 +83,7 @@ public class ImageView extends SurfaceView implements SurfaceHolder.Callback { void drawCanvas() { synchronized (holder) { - if (cantTouchThis) + if (cantTouchThis || bitmap == null) return; Canvas canvas = null; try { diff --git a/app/src/main/java/xdsopl/robot36/MainActivity.java b/app/src/main/java/xdsopl/robot36/MainActivity.java index ac9bcf5..e9f4c9b 100644 --- a/app/src/main/java/xdsopl/robot36/MainActivity.java +++ b/app/src/main/java/xdsopl/robot36/MainActivity.java @@ -240,6 +240,9 @@ public class MainActivity extends Activity { case R.id.action_wrasseSC2_180_mode: decoder.wrasseSC2_180_mode(); return true; + case R.id.action_pd180_mode: + decoder.pd180_mode(); + return true; } return super.onOptionsItemSelected(item); } diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index a5d2391..56b1d3b 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -42,6 +42,8 @@ android:orderInCategory="100" android:showAsAction="never" /> + Raw Mode Robot36 Mode Robot72 Mode + PD180 Mode Martin1 Mode Martin2 Mode Scottie1 Mode diff --git a/app/src/main/rs/calibration_detector.rsh b/app/src/main/rs/calibration_detector.rsh index d189111..02d87ab 100644 --- a/app/src/main/rs/calibration_detector.rsh +++ b/app/src/main/rs/calibration_detector.rsh @@ -114,6 +114,8 @@ static int calibration_detector(float dat_value, float dat_amp, float cnt_amp, i return mode_scottieDX; case 0xb7: return mode_wrasseSC2_180; + case 0x60: + return mode_pd180; default: return -1; } diff --git a/app/src/main/rs/constants.rsh b/app/src/main/rs/constants.rsh index 9e3bb0b..5d7a492 100644 --- a/app/src/main/rs/constants.rsh +++ b/app/src/main/rs/constants.rsh @@ -22,6 +22,7 @@ static const int decoder_robot36 = 1; static const int decoder_yuv = 2; static const int decoder_rgb = 3; static const int decoder_scottie = 4; +static const int decoder_pd = 5; static const int mode_raw = 0; static const int mode_robot36 = 1; @@ -32,6 +33,7 @@ static const int mode_scottie1 = 5; static const int mode_scottie2 = 6; static const int mode_scottieDX = 7; static const int mode_wrasseSC2_180 = 8; +static const int mode_pd180 = 9; static const float sync_buildup_ms = 1.1f; static const float scanline_tolerance = 0.05f; @@ -43,5 +45,6 @@ static const float scottie1_scanline_ms = 428.22f; static const float scottie2_scanline_ms = 277.692f; static const float scottieDX_scanline_ms = 1050.3f; static const float wrasseSC2_180_scanline_ms = 711.0225f; +static const float pd180_scanline_ms = 754.24f; #endif \ No newline at end of file diff --git a/app/src/main/rs/decoder.rs b/app/src/main/rs/decoder.rs index 3b139f6..739d536 100644 --- a/app/src/main/rs/decoder.rs +++ b/app/src/main/rs/decoder.rs @@ -99,7 +99,7 @@ static void robot36_decoder(int sync_timeout) if (parity) { odd_sync_pos = prev_sync_pos; int even_vpos = vpos; - int odd_vpos = (vpos + 1) % maximum_height; + int odd_vpos = (vpos + 1) % freerun_height; for (int i = 0; i < bitmap_width; ++i) { uchar even_y = value_blur(i, even_sync_pos + y_begin, even_sync_pos + y_end); uchar v = value_blur(i, even_sync_pos + v_begin, even_sync_pos + v_end); @@ -145,6 +145,37 @@ static void yuv_decoder() ++vpos; } +static void pd_decoder() +{ + if (debug_mode) { + for (int i = 0; i < bitmap_width; ++i) { + uchar r, g, b; + r = g = b = value_blur(i, prev_sync_pos, sync_pos); + int pos = (i * (sync_pos - prev_sync_pos) + (sync_pos - prev_sync_pos) / 2) / bitmap_width; + if (v_begin <= pos && pos < v_end) + g = b = 0; + if ((y_even_begin <= pos && pos < y_even_end) || (y_odd_begin <= pos && pos < y_odd_end)) + r = b = 0; + if (u_begin <= pos && pos < u_end) + r = g = 0; + pixel_buffer[bitmap_width * vpos + i] = rgb(r, g, b); + } + ++vpos; + } else { + int even_vpos = vpos; + int odd_vpos = (vpos + 1) % freerun_height; + for (int i = 0; i < bitmap_width; ++i) { + uchar odd_y = value_blur(i, y_odd_begin + prev_sync_pos, y_odd_end + prev_sync_pos); + uchar u = value_blur(i, u_begin + prev_sync_pos, u_end + prev_sync_pos); + uchar v = value_blur(i, v_begin + prev_sync_pos, v_end + prev_sync_pos); + uchar even_y = value_blur(i, y_even_begin + prev_sync_pos, y_even_end + prev_sync_pos); + pixel_buffer[bitmap_width * even_vpos + i] = yuv(even_y, u, v); + pixel_buffer[bitmap_width * odd_vpos + i] = yuv(odd_y, u, v); + } + vpos += 2; + } +} + static void rgb_decoder() { for (int i = 0; i < bitmap_width; ++i) { @@ -306,6 +337,9 @@ void decode(int samples) { case decoder_robot36: robot36_decoder(sync_timeout); break; + case decoder_pd: + pd_decoder(); + break; case decoder_yuv: yuv_decoder(); break; @@ -320,8 +354,8 @@ void decode(int samples) { } if (vpos >= bitmap_height) save_buffer(); - if (vpos >= maximum_height) - vpos -= maximum_height; + if (vpos >= freerun_height) + vpos -= freerun_height; seperator_counter = 0; } } diff --git a/app/src/main/rs/initialization.rsh b/app/src/main/rs/initialization.rsh index 77653db..9a736d7 100644 --- a/app/src/main/rs/initialization.rsh +++ b/app/src/main/rs/initialization.rsh @@ -56,6 +56,7 @@ void initialize(float rate, int length, int iw, int ih, int sw, int sh, int sgw, scottie2_scanline_length = round((scottie2_scanline_ms * sample_rate) / 1000.0f); scottieDX_scanline_length = round((scottieDX_scanline_ms * sample_rate) / 1000.0f); wrasseSC2_180_scanline_length = round((wrasseSC2_180_scanline_ms * sample_rate) / 1000.0f); + pd180_scanline_length = round((pd180_scanline_ms * sample_rate) / 1000.0f); const float pairwise_minimum_of_scanline_time_distances = 0.018226f; maximum_absolute_deviaton = 0.5f * pairwise_minimum_of_scanline_time_distances * sample_rate; diff --git a/app/src/main/rs/modes.rsh b/app/src/main/rs/modes.rsh index 0c5afaa..cc81b35 100644 --- a/app/src/main/rs/modes.rsh +++ b/app/src/main/rs/modes.rsh @@ -21,6 +21,10 @@ limitations under the License. #include "state.rsh" #include "exports.rsh" +static int freerun_reserve(int height) +{ + return (height * 3) / 2; +} void toggle_auto() { automatic_mode_detection ^= 1; @@ -34,6 +38,7 @@ void raw_mode() blur_power = -1; *current_mode = mode_raw; current_decoder = decoder_raw; + freerun_height = maximum_height; bitmap_width = maximum_width; bitmap_height = maximum_height; sync_length = minimum_sync_length; @@ -48,6 +53,7 @@ void robot36_mode() current_decoder = decoder_robot36; bitmap_width = 320; bitmap_height = 240; + freerun_height = freerun_reserve(bitmap_height); const float tolerance = 0.8f; const float sync_ms = 9.0f; const float sync_porch_ms = 3.0f; @@ -83,6 +89,7 @@ void robot72_mode() current_decoder = decoder_yuv; bitmap_width = 320; bitmap_height = 240; + freerun_height = freerun_reserve(bitmap_height); const float tolerance = 0.8f; const float sync_ms = 9.0f; const float sync_porch_ms = 3.0f; @@ -119,6 +126,42 @@ void robot72_mode() minimum_length = ((1.0f - scanline_tolerance) * robot72_scanline_ms * sample_rate) / 1000.0f; maximum_length = ((1.0f + scanline_tolerance) * robot72_scanline_ms * sample_rate) / 1000.0f; } +void pd180_mode() +{ + blur_power = 3; + *current_mode = mode_pd180; + current_decoder = decoder_pd; + bitmap_width = 640; + bitmap_height = 496; + freerun_height = freerun_reserve(bitmap_height); + const float tolerance = 0.8f; + const float sync_ms = 20.0f; + const float porch_ms = 2.08f; + const float yuv_scan_ms = 183.04f; + sync_length = tolerance * (sync_ms * sample_rate) / 1000.0f; + + float y_odd_begin_ms = porch_ms; + float y_odd_end_ms = y_odd_begin_ms + yuv_scan_ms; + float v_begin_ms = y_odd_end_ms; + float v_end_ms = v_begin_ms + yuv_scan_ms; + float u_begin_ms = v_end_ms; + float u_end_ms = u_begin_ms + yuv_scan_ms; + float y_even_begin_ms = u_end_ms; + float y_even_end_ms = y_even_begin_ms + yuv_scan_ms; + + y_odd_begin = round((y_odd_begin_ms * sample_rate) / 1000.0f); + y_odd_end = round((y_odd_end_ms * sample_rate) / 1000.0f); + v_begin = round((v_begin_ms * sample_rate) / 1000.0f); + v_end = round((v_end_ms * sample_rate) / 1000.0f); + u_begin = round((u_begin_ms * sample_rate) / 1000.0f); + u_end = round((u_end_ms * sample_rate) / 1000.0f); + y_even_begin = round((y_even_begin_ms * sample_rate) / 1000.0f); + y_even_end = round((y_even_end_ms * sample_rate) / 1000.0f); + + scanline_length = pd180_scanline_length; + minimum_length = ((1.0f - scanline_tolerance) * pd180_scanline_ms * sample_rate) / 1000.0f; + maximum_length = ((1.0f + scanline_tolerance) * pd180_scanline_ms * sample_rate) / 1000.0f; +} void martin1_mode() { blur_power = 3; @@ -126,6 +169,7 @@ void martin1_mode() current_decoder = decoder_rgb; bitmap_width = 320; bitmap_height = 256; + freerun_height = freerun_reserve(bitmap_height); const float tolerance = 0.5f; const float sync_ms = 4.862f; const float sync_porch_ms = 0.572f; @@ -159,6 +203,7 @@ void martin2_mode() current_decoder = decoder_rgb; bitmap_width = 320; bitmap_height = 256; + freerun_height = freerun_reserve(bitmap_height); const float tolerance = 0.5f; const float sync_ms = 4.862f; const float sync_porch_ms = 0.572f; @@ -192,6 +237,7 @@ void scottie1_mode() current_decoder = decoder_scottie; bitmap_width = 320; bitmap_height = 256; + freerun_height = freerun_reserve(bitmap_height); const float tolerance = 0.8f; const float sync_ms = 9.0f; const float sync_porch_ms = 1.5f; @@ -225,6 +271,7 @@ void scottie2_mode() current_decoder = decoder_scottie; bitmap_width = 320; bitmap_height = 256; + freerun_height = freerun_reserve(bitmap_height); const float tolerance = 0.8f; const float sync_ms = 9.0f; const float sync_porch_ms = 1.5f; @@ -258,6 +305,7 @@ void scottieDX_mode() current_decoder = decoder_scottie; bitmap_width = 320; bitmap_height = 256; + freerun_height = freerun_reserve(bitmap_height); const float tolerance = 0.8f; const float sync_ms = 9.0f; const float sync_porch_ms = 1.5f; @@ -291,6 +339,7 @@ void wrasseSC2_180_mode() current_decoder = decoder_rgb; bitmap_width = 320; bitmap_height = 256; + freerun_height = freerun_reserve(bitmap_height); const float tolerance = 0.5f; const float sync_ms = 5.5225f; const float sync_porch_ms = 0.5f; @@ -345,6 +394,9 @@ static void switch_mode(int new_mode) case mode_wrasseSC2_180: wrasseSC2_180_mode(); break; + case mode_pd180: + pd180_mode(); + break; default: return; } diff --git a/app/src/main/rs/scanline_estimator.rsh b/app/src/main/rs/scanline_estimator.rsh index abe68c1..fac7bc3 100644 --- a/app/src/main/rs/scanline_estimator.rsh +++ b/app/src/main/rs/scanline_estimator.rsh @@ -53,15 +53,19 @@ static int scanline_estimator(int sync_level) int scottie2_adev = abs(mean - scottie2_scanline_length); int scottieDX_adev = abs(mean - scottieDX_scanline_length); int wrasseSC2_180_adev = abs(mean - wrasseSC2_180_scanline_length); + int pd180_adev = abs(mean - pd180_scanline_length); int min_adev = min( min( - min(robot36_adev, robot72_adev), - min(martin1_adev, martin2_adev) - ), min( - min(scottie1_adev, scottie2_adev), - min(scottieDX_adev, wrasseSC2_180_adev) - ) + min( + min(robot36_adev, robot72_adev), + min(martin1_adev, martin2_adev) + ), min( + min(scottie1_adev, scottie2_adev), + min(scottieDX_adev, wrasseSC2_180_adev) + ) + ), + pd180_adev ); if (min_adev > maximum_absolute_deviaton) @@ -82,6 +86,8 @@ static int scanline_estimator(int sync_level) return mode_scottieDX; else if (min_adev == wrasseSC2_180_adev) return mode_wrasseSC2_180; + else if (min_adev == pd180_adev) + return mode_pd180; return -1; } diff --git a/app/src/main/rs/state.rsh b/app/src/main/rs/state.rsh index 051d3f9..509116f 100644 --- a/app/src/main/rs/state.rsh +++ b/app/src/main/rs/state.rsh @@ -37,11 +37,13 @@ static int buffer_length, buffer_mask, buffer_pos; static int buffer_cleared; static int bitmap_width, bitmap_height; static int maximum_width, maximum_height; +static int freerun_height; static int spectrum_width, spectrum_height; static int spectrogram_width, spectrogram_height; static int sync_length, sync_counter, vpos, hpos; static int seperator_counter, seperator_length; static int u_sep_begin, u_sep_end, v_sep_begin, v_sep_end; +static int y_even_begin, y_even_end, y_odd_begin, y_odd_end; static int y_begin, y_end, u_begin, u_end, v_begin, v_end; static int r_begin, r_end, b_begin, b_end, g_begin, g_end; static int sync_buildup_length; @@ -53,5 +55,6 @@ static int scottie1_scanline_length; static int scottie2_scanline_length; static int scottieDX_scanline_length; static int wrasseSC2_180_scanline_length; +static int pd180_scanline_length; #endif \ No newline at end of file