2015年12月28日 星期一

ImageView寬高時保持原比例

我只是要把一張bitmap放到App上置中秀出來, 並且可以保持原比例的放滿整個畫面.
為這樣子的功能Google了蠻久的, 因為總覺得不需要太複雜的設定, 就要可以達到這樣子的目的才對啊. 最後終於發現為什麼我一開始無法保持原比例放大了. 目前的結論如下:

layout的xml設定如下(它是一個LinearLayout 再加一個ImageView)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:gravity="center" >
    <ImageView android:id="@+id/template_imageview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
    </ImageView>
</LinearLayout>
android:layout_height="match_parent" <=== 很多人說要用"wrap_content"

然後在Java的程式裏面
ImageView imageView = (ImageView) findViewById(R.id.template_imageview);
imageView.setImageBitmap(downloadBitmap);
imageView.setAdjustViewBounds(true);
最重要的一行imageView.setAdjustViewBounds(true); 不設定為true的話無法放大圖片.

避免螢幕旋轉再次自動執行onCreate()

寫了一個程式, 裏面放了三個ListView, 依情況分別設定想要秀出來的ListView, 這時才發現, 當我旋轉手機後, 居然會重新呼叫onCreate(), 整個流程就從頭來過了.

查了一下官網的資料Handling The Change, 有教要如何避開這種情況. 主要是要做2個修正.
(1)AndroidManifest.xml (2)新增onConfigurationChanged

這兩個修改步驟如下:
(1)在AndroidManifest.xml裏面加入下圖, 紅色框框的文字.
新增的設定為android:configChanges="orientation|keyboardHidden|screenSize"
(2)在你的Activity.java檔案裏, 加入下面的程式碼
@Overridepublic void onConfigurationChanged(Configuration newConfig){
    super.onConfigurationChanged(newConfig);

}

根據實驗, 這樣子的修改後, 真的不會又被呼叫一次onCreate()了.

2015年12月26日 星期六

Modern C - Jens Gustedt

Jserv推廌的一本電子書, 由在 INRIA (法國國立電腦科學及自動化研究院) 任職的 Jens Gustedt 撰寫. 主要是探討新的 C 語言規格和應用規範.


2015年12月24日 星期四

Resterization

發現一張好圖, 快速的說明了什麼是Resterization.

資料來源:
Android性能优化典范

行動上網速度比較表

紀錄一下這張表, 它顯示了各個規格的上/下載速度.

資料來源:
智慧型手機螢幕上方E、o、G、3G、H、H+、4G、4G+的意義

2015年12月23日 星期三

貨幣系統真相(Hidden Secrets of Money)

底下是由Mike Maloney所建立的一個以另類觀點去簡介現代金融的影片網站。目前共六集. https://www.hiddensecretsofmoney.com/
Currency vs. Money 通貨VS貨幣 第一集 (簡中版本)
Seven Stages of Empire 帝國的七個階段 第二集 (簡中版本)
From Dollar Crisis To Golden Opportunity 從美元危機到黃金機會 第三集 (簡體中文)
The Biggest Scam In The History Of Mankind (In 7 Easy Steps) 人類史上的最大騙局 第四集 中文
ULTIMATE HISTORY OF MONEY - Hidden Secrets Of Money Ep 5 - Mike Maloney 貨幣墮落引發的孿生險象 第五集 (簡體中文)
Rollercoaster Crash: Top 4 Reasons For Deflation - Hidden Secrets Of Money 6 (缺中文版)

2015年12月10日 星期四

數學函式操

動畫版:

via GIPHY

手繪版:

2015年12月7日 星期一

Audio Wave Format Specification

WAV File - Waveform Audio File Format (WAVE, or more commonly known as WAV due to its filename extension).
是微软與IBM公司所開發在個人電腦儲存音訊串流的編碼格式,它受到Windows平台的應用軟體之廣泛支援,也是使用者經常使用的指定規格之一。WAV音頻格式沒有經過壓縮(原則上只有在類比轉數位這個過程會失真),所以音質不會出現失真的情況,但相對地,它的檔案體積在各種音頻格式中是比較大的。一般音樂CD片也是由WAV檔編輯而成。



底下的網頁講的也蠻不錯的
http://soundfile.sapp.org/doc/WaveFormat/

Little Endian注意事項:
裏面的Size存放格式都是Little Endian, 因此讀入後要轉換一下, 在fdk-aac的範例程式轉換函式入下:
static uint32_t read_int32(struct wav_reader* wr) {
        uint32_t value = 0;
        value |= fgetc(wr->wav) <<  0;
        value |= fgetc(wr->wav) <<  8;
        value |= fgetc(wr->wav) << 16;
        value |= fgetc(wr->wav) << 24;
        return value;
}
你也可以在include byteswap.h後使用bswap_32()函式
#include <stdio.h>
#include <stdlib.h>
#include <byteswap.h>

int main(int argc, char** argv){
        unsigned int a = 0x46000600;
        printf("%08x\n", bswap_32(a));
}


底下的範例檔案是使用ffmpeg將pcm資料轉成wav檔,整個wav檔的大小為778318bytes

52, 49, 46, 46代表"RIFF".
000be046代表扣掉目前的8個bytes後面的資料長度, 所以是778310+8=778318bytes.
57, 41 56, 45代表"WAVE".
66, 6d, 74, 20代表"fmt ".
00000010代表後面有接著16bytes的fmt資料(01 00 01 00 11 2b 00 00 22 56 00 00 02 00 10 00)
    0001 => Audio Format = 1(PCM)
    0001 => NumChannels = 1 channel
    00002b11 => 11025 Sample Rate
    00005622 => 22050 ByteRate
    0002 => BlockAlign = 2
    0010 => BitsPerSample = 16
4c, 49, 53, 54代表"LIST".
0000001a代表後面有接著26bytes的list資料(49 4e 46 4f 49 53 46 54 0e 00 00 00 4c 61 76 66 35 37 2e 31 39 2e 31 30 30 00)
64, 61, 74, 61代表"data".
000be000代表後面接著778240的資料. 所以778240+78=778318bytes

參考:
https://www.aelius.com/njh/wavemetatools/

2015年12月1日 星期二

英文月份的由來


一年有十二個月的英文名稱大都起源於拉丁文,有些更源自希臘、羅馬神話中的人物。

January 一月
取名自希臘、羅馬神話中的門神「Janus」,拉丁文為Ianuarius。他有兩副面孔,一張用來回顧過往,另一張則用來眺望未來,他也負責日出和日落,是象徵「開始」和「結束」之神。因此便取自他的名字,作為每年第一個月的名稱。我們可以在這個月回顧過去,展望新的一年。最初古羅馬曆法沒有這個月份。

February 二月
起源自古羅馬的「淨化節(Februa)」,拉丁文為Februarius,羅馬人民在每年二月初的節日—Februarius 都會宰殺牲畜、飲酒慶祝。在這一天,人們還用名叫 Februa 的一種牛與草混合製成的鞭子來抽打不孕的婦女,藉由此儀式讓該婦女能夠順利懷孕生子。這個拉丁文 Februarius 演變而成的 February來稱呼二月。最初古羅馬曆法沒有這個月份。

March 三月
本來是羅馬舊曆法當中一年的開始,也就是一月。之後由於凱撒大帝改革曆法,把這個月挪成了每年的第三個月。加上在羅馬的傳統中,出征打仗的時間都是在這個月,所以便沿用戰神 Mars 之名,稱三月為 Mars。古羅馬曆法的第一個月Martius。

April 四月
起源自「阿芙洛蒂特(Aphrodite)」,為希臘的愛神、美神、生育神,羅馬人將其轉化為「維納斯Venus」,四月是羅馬的春天,此時大地百花齊放、美不勝收,人們因此用拉丁文中的「開花的日子」(April)來代表四月。古羅馬曆法的第二個月Maius。

June 六月
起源自「朱諾(Juno)」,為羅馬神話中的天后,也是羅馬天神Jupiter的妻子,她也是一位保護女性的女神,負責婚姻,生育等工作,也因此六月是最適合結婚的月份,古羅馬曆法的第四個月Junius,是因為Juno在古羅馬有著十分崇高的地位,所以人們把六月奉獻給她,以她的名字來命名六月。

July 七月
原是古羅馬曆法的第五個月Quintilis,羅馬的朱里斯.凱撒大帝遇刺身亡後,將軍 Marcus Antonius 為紀念其宏偉事蹟,建議用他的名字 Julius 來命名其誕生的七月,因而取其名Gaius Julius Caesar中的Julius重新命名月份,

August 八月
原是古羅馬曆法的第六個月Sextilis,凱撒大帝死後,他的甥孫兼養子屋大維成為羅馬皇帝,為了表示跟凱撒一樣偉大,他也用自己的名字來命名月份。因為元老院在八月授予他「奧古斯都」(Augustus)的尊號,所以他決定將八月改成這個名稱。原來的八月比七月還少了一天,屋大維想跟凱撒平起平坐,決定從二月挪一天加到八月,讓八月跟七月都是三十一天。

September 九月
原是古羅馬曆法的第七個月September,拉丁文的7為septem。但是凱撒大帝改革曆法後,這一個月就變成了九月。

October 十月
原是古羅馬曆法的第八個月October,拉丁文的8為octo。人們在改革曆法後依舊習慣使用本來的稱呼,沿用到最後,英文十月就變成了 October。

November 十一月
原是古羅馬曆法的第九個月November,拉丁文的9為novem。羅馬皇帝奧古斯都和凱撒都有了自已名字命名的月份,羅馬市民和元老院要求當時的羅馬皇帝梯比里烏斯用他的名字命名11月,但梯比里烏斯沒有同意,他明智的對大家說,如果羅馬每個皇帝都用自己的名字來命名月份,那出現第十三個皇帝怎麼辦?因此十一月跟後來的九、十月一樣,使用舊有的名稱。

December 十二月
原是古羅馬曆法的第十個月December,拉丁文的10為decem。據說羅馬皇帝琉西烏斯要把一年中最後一個月用他的情婦Amagonius的名字來命名,但遭到元老院的反對。因此這個月在改革曆法後依舊被人們拿來稱呼十二月,使得 December 演變為英文的十二月。

資料來源: 網路到處搜集而來,可能有誤,當故事看看就好!

Android各個版本的使用狀況分析表

在Google的Android Dashboards頁面, 就有每個版本的使用率可以參考.
下圖是2015年11月份的狀況

Alsa Audio Capture

最近在試Camera Digital Microphone, 它基本上是走Alsa的架構,
因此找個Alsa Audio Capture的範例程式來做實驗.
參考資料來自於: Linux Journal Introduction to Sound Programming with ALSA

/*

   This example reads from the default PCM device
   and writes to standard output for 5 seconds of data.

 */

/* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_API

#include <alsa/asoundlib.h>

int main() {
        long loops;
        int rc;
        int size;
        snd_pcm_t *handle;
        snd_pcm_hw_params_t *params;
        unsigned int val;
        int dir;
        snd_pcm_uframes_t frames;
        char *buffer;

        /* Open PCM device for recording (capture). */
        rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0);
        if (rc < 0) {
                fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
                exit(1);
        }

        /* Allocate a hardware parameters object. */
        snd_pcm_hw_params_alloca(&params);

        /* Fill it in with default values. */
        snd_pcm_hw_params_any(handle, params);

        /* Set the desired hardware parameters. */

        /* Interleaved mode */
        snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);

        /* Signed 16-bit little-endian format */
        snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);

        /* Two channels (stereo) */
        snd_pcm_hw_params_set_channels(handle, params, 2);

        /* 44100 bits/second sampling rate (CD quality) */
        val = 44100;
        snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);

        /* Set period size to 32 frames. */
        frames = 32;
        snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);

        /* Write the parameters to the driver */
        rc = snd_pcm_hw_params(handle, params);
        if (rc < 0) {
                fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
                exit(1);
        }

        /* Use a buffer large enough to hold one period */
        snd_pcm_hw_params_get_period_size(params, &frames, &dir);
        size = frames * 4; /* 2 bytes/sample, 2 channels */
        buffer = (char *) malloc(size);

        /* We want to loop for 5 seconds */
        snd_pcm_hw_params_get_period_time(params, &val, &dir);
        loops = 5000000 / val;

        while (loops > 0) {
                loops--;
                rc = snd_pcm_readi(handle, buffer, frames);
                if (rc == -EPIPE) {
                        /* EPIPE means overrun */
                        fprintf(stderr, "overrun occurred\n");
                        snd_pcm_prepare(handle);
                } else if (rc < 0) {
                        fprintf(stderr, "error from read: %s\n", snd_strerror(rc));
                } else if (rc != (int)frames) {
                        fprintf(stderr, "short read, read %d frames\n", rc);
                }
                rc = write(1, buffer, size);
                if (rc != size)
                        fprintf(stderr, "short write: wrote %d bytes\n", rc);
        }

        snd_pcm_drain(handle);
        snd_pcm_close(handle);
        free(buffer);

        return 0;
}

目前錄出來的PCM聲音檔, 我是在ubuntu上用mplayer去播放
mplayer -rawaudio samplesize=2:channels=2:rate=11025 -demuxer rawaudio test.raw

使用ffmpeg將PCM檔轉WAV檔
ffmpeg -f s16le -ar 11025 -ac 2 -i ./test.pcm ./test.wav

  • -f s16le … signed 16-bit little endian samples
  • -ar 11025 … sample rate 11025Hz
  • -ac 2 … 2 channels (stereo)
  • -i test.pcm … input file
  • test.wav … output file
snd_pcm_readi這裏有遇到一個有趣的問題, 它回傳的值是audio frames的數量.
當你的資料是設定為16bits, 2 channles時, 一個frames的大小為4 bytes.