Xwork's Blog

The lord is waiting to take your hand.

El Video Correcto #4 - Flac Vs MP3 #2.

No hay comentarios.
Hola de nuevo a todos, el día de hoy vamos a continuar con la revisión del "por qué" el formato FLAC es mejor al formato MP3.

En el post anterior, dije que el formato FLAC es mejor a el MP3, ya que este comprime en lugar de eliminar. Vamos a ver una pequeña muestra de que tanto es lo que se elimina cuando pasamos de un formato a otro.

Para poder realizar la prueba, necesitas lo siguiente:


  1. Un archivo FLAC.
  2. Un archivo MP3.
  3. Un editor de audio (Yo uso Audacity).

Una vez que tenemos lo anterior, abriremos nuestro editor de audio e importaremos las pistas de audio.

Lo primero que haremos, es alinear las pistas, de tal modo que ambas empiecen en exactamente el mismo momento, si descargaste las canciones de muestra, en el archivo MP3 hay que cortar un poco y con ayuda del zoom, buscar que ambas inicien en el mismo instante.
Una vez alineadas ambas pistas, seleccionaremos la pista que corresponde al archivo mp3 y le aplicaremos el efecto de "inversión", no hay que confundirlo con "revertir", ya que uno lo que hace, es invertir "de arriba a abajo", mientras que el otro efecto lo hace "de izquierda a derecha", o mas técnicamente, uno invierte las onda por lo que los valles pasan a ser crestas (y viceversa).
En las ondas cuando sumamos dos ondas que son iguales pero invertidas, tenemos que se cancelan entres si, si aplicamos eso a nuestro audio, al mezclar las pistas, obtendremos, que los "sonidos" existentes en ambas se cancelaran y solo quedaran aquellos que estén ausentes en cualquiera de las pistas. En el caso de audacity, bastará reproducir las dos canciones al mismo tiempo y notarás de inmediato que solo se escucha una versión reducida y aguda de la canción original. Esto que escuchas, es todo lo que se pierde al momento de convertir a mp3.

Las siguientes imágenes muestran cómo se "ve" cada formato:
Formato MP3

Formato FLAC
Residuo al "sumar" las dos canciones.
El resultado lo puedes descargar para escucharlo, es importante que antes hayas escuchado los otros 2 archivos (eso si, recuerda eliminarlos a terminar de usarlos). Cómo notarás, el sonido es bajo y agudo, esa es una de las principales características del MP3, eliminar las frecuencias que la mayoría de las personas (en teoría) no escuchan más allá de los 20KHz, pero también es un hecho que hay personas (ademas de los niños), que pueden oír sonidos de hasta 32KHz.

Y bien, por ahora es todo, en el próximo post, veremos cómo convertir de FLAC a MP3 usando FFMPEG.

Los leo luego.

No hay comentarios. :

Publicar un comentario

El video correcto #3 -FLAC Vs MP3

No hay comentarios.
Hola de nuevo a todos, el día de hoy vamos a ver cual es la diferencia entre un archivo MP3 y un archivo FLAC


Hace poco, mi computadora murió y junto con ella, todos los archivos que se encontraban en el disco duro, una perdida considerable, pero no tan grave, puesto que tengo un respaldo de las cosas importantes en un disco duro externo. Cómo no tenia el presupuesto necesario para poder comprar un disco duro de 8TB, opté por comprar lo primero que encontrará, lo que conseguí, fue un disco duro de 80GB. Podría parecer bastante, pero suponiendo que todos los IDE's de desarrollo que uso, ocupan en conjunto 20 GB + 10GB del sistema operativo + los archivos que requiero utilizar, el espacio restante, fue realmente pequeño.
Actualmente no poseo mucha música, pero la poca que tengo, al estar en formato FLAC, ocupa un espacio considerable (en comparación al tradicional y compacto MP3).

Antes de seguir, el formato FLAC es el siguiente:
FLAC (son las siglas de Free Lossless Audio Codec) es un códec de audio que permite que el audio digital sea comprimido sin pérdidas de tal manera que el tamaño del archivo de audio se reduce sin que se pierda ningún tipo de información. El audio digital comprimido por el algoritmo de FLAC típicamente se puede reducir de 50 a 60% de su tamaño original,3​ y se descomprime en una copia idéntica de los datos de audio originales.
Por la calidad superior que estos poseen, es que los prefiero, pero ante la limitada capacidad del disco duro, decidí hacer una versión en MP3 de los archivos, para ver un ejemplo de cuantas es la diferencia entre uno y otro, veamos la información de la siguiente canción:

Archivo MP3 de la mejor calidad, 8 MB

Archivo FLAC con calidad buena (no superior) 26MB
Muchos no notan la diferencia entre un MP3 de máxima calidad y un FLAC promedio, pero por desgracia, yo si la notaba (antes porque ahora mi oído se ha gastado) y por eso trataba de "conseguir" la música en la mejor calidad posible.
En archivo MP3 se mutilan algunas frecuencias, que por lo general el oído no logra captar, pero en el archivo FLAC, todas las frecuencias se mantienen, y se comprimen, logrando que el sonido sea mucho más fiel al original.
Al deteriorarse mi oído, debo admitir que realmente, en el 60% de los casos ya no escucho ninguna diferencia entre un MP3 de alta calidad y un FLAC por lo que decidí crear una versión liviana. Lo importante de esto, es que podemos hacer una versión MP3 de un archivo FLAC; pero no el reves, crear un archivo FLAC de un MP3, es un desperdicio, cómo el MP3 literalmente fue "cortado", esas frecuencias faltantes ya no se pueden recuperar y estariamos haciendo un archivo pesado que realmente no valdría la pena.

Si quieres oír la diferencia entre FLAC y MP3, dejo una canción de muestra (que deberás de eliminar una vez que termines de comparar).

El archivo flac, lo puedes descargar de aqui.
El archivo mp3, lo puedes descargar de aqui.

Por ahora es todo, en el próximo post, veremos cómo crear un MP3 desde un archivo FLAC usando FFMPEG.

Los leo luego.

No hay comentarios. :

Publicar un comentario

Vamos a programar #46 - Código Bacon (ver Java android)

No hay comentarios.
Hola de nuevo a todos, el día de hoy vamos a ver un poco mas sobre el código Bacon y cómo implementar una aplicación en android que haga todo el trabajo sucio por nosotros.
En post anteriores vimos cómo hacer la misma aplicación para C# (escritorio) y Javascript (Web), en esta ocasión, todo el post será solo para mostrar la app, puesto que las funciones que se emplean son exactamente las mismas que la versión de C#. El código completo es el siguiente:

package com.mdev.baconiancipher;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity {
	EditText ETInput, ETInput2, ETPreResult, ETResult;
	Button BtnPreCipher, BtnCipher;
	String[] Values = new String[]{"AAAAA", "AAAAB", "AAABA",
				"AAABB", "AABAA", "AABAB", "AABBA", "AABBB", "ABAAA", "ABAAA",
				"ABAAB", "ABABA", "ABABB", "ABBAA", "ABBAB", "ABBBA", "ABBBB",
				"BAAAA", "BAAAB", "BAABA", "BAABB", "BAABB", "BABAA", "BABAB",
				"BABBA", "BABBB"};


	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		ETInput = findViewById(R.id.ETInput);
		ETInput2 = findViewById(R.id.ETInput2);
		ETPreResult = findViewById(R.id.ETPreResult);
		ETResult = findViewById(R.id.ETResult);
		BtnPreCipher = findViewById(R.id.BtnPreCipher);
		BtnCipher = findViewById(R.id.BtnCipher);

		BtnPreCipher.setOnClickListener(new View.OnClickListener() {
				@Override
				public void onClick(View v) {
					ETPreResult.setText(CharToBaconianCode(ETInput.getText().toString()));
				}
			}
		);
		BtnCipher.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				ETResult.setText(FinalCipher(ETPreResult.getText().toString(),ETInput2.getText().toString()));
			}
		});
	}

	private String CharToBaconianCode(String Input)
	{
		Input = Input.toUpperCase();
		char[] Letras = Input.toCharArray();
		String OutValue = "";
		for (int X = 0; X < Letras.length; X++)
		{
			if ((byte)Letras[X] < 91 && (byte)Letras[X] > 64)
			{
				OutValue += Values[(byte)Letras[X] - 65];// + " ";
			}
		}
		return OutValue;
	}
	private boolean IsLower(byte Code)
	{
		if (Code > 96 && Code < 123)
			return true;
		else
			return false;
	}
	private String FinalCipher(String PreCipher, String Phrase)
	{
		if (PreCipher.length() != Phrase.length())
		{
			ShowDialog("Error","Las longitudes del pre-cifrado y la frase para insertarlo no coinciden");
			return "Error";
		}
		char[] PreCipherChars = PreCipher.toCharArray();
		char[] PhraseChars = Phrase.toCharArray();
		String FinalResult = "";
		for (int Y = 0; Y < PhraseChars.length; Y++)
		{
			if ((byte)PreCipherChars[Y] == 65)
			{
				if (IsLower((byte)PhraseChars[Y]))
					FinalResult += PhraseChars[Y];
				else
					FinalResult += (char)(PhraseChars[Y] + 32);
			}
			else
			{
				if (!IsLower((byte)PhraseChars[Y]))
					FinalResult += PhraseChars[Y];
				else
					FinalResult += (char)(PhraseChars[Y] - 32);
			}
		}
		return FinalResult;
	}
	//Mostrar dialog de manera sencilla
	private void ShowDialog(String Title, String Caption)
	{
		new AlertDialog.Builder(this)
				.setTitle(Title)
				.setMessage(Caption)
				.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						// algo
					}
				})
				.setIcon(android.R.drawable.ic_dialog_alert)
				.show();
	}
}


Cómo notarás, no hay ningún cambio significativo (y no lo habrá en unos días debido a que mi PC murió y no cuento con el tiempo cómo para arreglarlo). Por ahora dejo el código fuente y el APK ya compilado para que los descargues de mi dropbox. Las actualizaciones se harán juntas para las 3 versiones en alguno de los próximos post

Por ahora es todo, los leo luego.

No hay comentarios. :

Publicar un comentario

Vamos a programar #45 - Código Bacon (ver. Javascript).

No hay comentarios.
Hola de nuevo a todos, el día de hoy vamos a ver cómo crear una aplicación en javascript que sirva para aplicar el código Bacon en un texto.

En el post anterior hicimos una versión en C# para escritorio, el día de hoy vamos a realizar una versión para la Web.

El código.

El codigo en javascript que sirve para cifrar una frase usando el código Bacon es el siguiente:

<html>
	<head>
	<title>Bacon Cipher</title>
	<style type="text/css">
		.FormBacon{
			font: 95% Arial, Helvetica, sans-serif;
			max-width: 600px;
			margin: 10px auto;
			padding: 16px;
			background: #F9F9F9;
		}
		.FormBacon h1{
			font-size: 140%;
			text-align: center;
		}
		.h1c
		{
			font-size: 16px;
		}
		.textareaV
		{
			width: 100%;
			height: 150px;
			padding: 2px 5px;
			box-sizing: border-box;
			border: 2px solid #999;
			border-radius: 4px;
			resize: none;
			-webkit-transition-duration: 0.4s; /* Safari */
			transition-duration: 0.4s;
		}

		.textareaV:focus
		{
			width: 100%;
			height: 150px;
			padding: 2px 5px;
			box-sizing: border-box;
			border: 2px solid #26c6da;
			border-radius: 4px;
			resize: none;
		}

		.TextV
		{
			width: 100%;
			box-sizing: border-box;
			border: 2px solid #999;
			border-radius: 4px;
		}

		.ButtonV
		{
		width: 100%;
			background-color: #26c6da;
			border: none;
			color: white;
			padding: 15px 32px;
			text-align: center;
			text-decoration: none;
			display: inline-block;
			-webkit-transition-duration: 0.4s; /* Safari */
			transition-duration: 0.4s;
		}

		.ButtonV:hover
		{
		width: 100%;
			background-color: #30e0e0;
			border: none;
			color: white;
			padding: 15px 32px;
			text-align: center;
			text-decoration: none;
			display: inline-block;
		}
		</style>
		<script type="text/javascript">
		var Values =["AAAAA", "AAAAB", "AAABA",
			"AAABB", "AABAA", "AABAB", "AABBA", "AABBB", "ABAAA", "ABAAA",
			"ABAAB", "ABABA", "ABABB", "ABBAA", "ABBAB", "ABBBA", "ABBBB",
			"BAAAA", "BAAAB", "BAABA", "BAABB", "BAABB", "BABAA", "BABAB",
			"BABBA", "BABBB"];
		function PhraseToArray(Text){
			var Out = [];
			for(var i = 0; i < Text.length; i++){
				var CodeChar = Text.charCodeAt(i);
				Out.push(CodeChar);
			}
			return Out;
		}
		function CharToBaconianCode(){
		//debugger;
			Input = document.getElementById('InputText').value;
			Input = Input.toUpperCase();
			var Letras = PhraseToArray(Input);
			var OutValue = "";
			for (var X = 0; X < Letras.length; X++)
			{
				if (Letras[X] < 91 && Letras[X] > 64)
				{
					OutValue += Values[Letras[X] - 65];// + " ";
				}
			}
			document.getElementById('PreResult').value = OutValue;
			return OutValue;
		}
		function IsLower(Code)
		{
			if (Code > 96 && Code < 123)
				return true;
			else
				return false;
		}
		function FinalCipher()
		{
		//debugger;
			var PreCipher = document.getElementById('PreResult').value;
			var Phrase = document.getElementById('Phrase2').value;
			if (PreCipher.length != Phrase.length)
			{
				alert("Las longitudes del pre-cifrado y la frase para insertarlo no coinciden");
				return "Error";
			}
			var PreCipherChars = PhraseToArray(PreCipher);
			var PhraseChars = PhraseToArray(Phrase);
			var FinalResult = "";//string
			for (var Y = 0; Y < PhraseChars.length; Y++)
			{
				if (PreCipherChars[Y] == 65)
				{
					if (IsLower(PhraseChars[Y]))
						FinalResult += String.fromCharCode(PhraseChars[Y]);
					else
						FinalResult += String.fromCharCode(PhraseChars[Y] + 32);
				}
				else
				{
					if (!IsLower(PhraseChars[Y]))
						FinalResult += String.fromCharCode(PhraseChars[Y]);
					else
						FinalResult += String.fromCharCode(PhraseChars[Y] - 32);
				}
			}
			document.getElementById('Result').value = FinalResult;
		}
		</script>
	</head>
	<body>
		<div class="FormBacon">
			<br />
			<h1>Código Bacon</h1><br />
			<br />
			<form>
				<span class="h1c">Frase a encriptar:</span>
				<br />
				<input class="TextV" id="InputText" type="text"></input><br />
				<br />
				<input class="ButtonV" id="Encrypt" onclick="CharToBaconianCode()" type="button" value="Pre-cifrar" /><br />
				<br/>
				<span class"h1c">Resultado del Pre-cifrado</span><br/>
				<br/>
				<textarea class="textareaV" id="PreResult" rows="5"></textarea><br/>
				<br/>
				<span class="h1c">Frase para insertar</span><br /><br/>
				<input class="TextV" id="Phrase2" type="text" /><br />
				<br />
				<input class="ButtonV" id="UnEncrypt" onclick="FinalCipher()" type="button" value="Cifrar" /><br />
				<br />
				<span class="h1c">Resultado</span>
				<textarea class="textareaV" id="Result" rows="5"></textarea><br/><br/>
			</form>
		</div>
	</body>
</html>
 
La aplicación consiste de cinco partes; de las cuales cuatro son funciones y una más, es una variable que se usará para almacenar las constantes del cifrado
Primero definimos una nueva variable, será una matriz (que ya dije para que se usa). Luego creamos una funcion que reemplazará a la función de C# "string.toArray()", esta función es "PhraseToArray()"; recibe un parámetro que será el texto que queremos convertir a una matriz de números, hay que recordar que en el caso de la función en C#, cuando la llamamos, esta devuelve una matriz del tipo "char", en este caso, cómo vamos a usar el valor ASCII de esa letra, directamente guardamos en la matriz el valor resultante de llamar a la función "charCodeAt()", si hacemos memoria, está función, lo que hace es obtener el código ASCII de la letra (o símbolo) que se le pasa cómo argumento, entonces, solamente hacemos un ciclo "for" que recorra cada letra desde el inicio al final del texto que se ingreso cómo parámetro en la función "PhraseToArray()". Finalmente, está función devuelve una matriz con números que representa el código ASCII de cada letra.

La siguiente función es "CharToBaconianCode()", cómo su nombre lo dice, está función lo que hace, es convertir cada letra en su equivalente en el código Bacon. La única diferencia con la función de C#, es que esta no recibe parámetros, lo que hace para obtener el texto sobre el cual trabajara, es usar la función "document.getElementById('')" y obtener el valor de la caja de texto. El resto del proceso es similar, solamente que no hace conversiones de "char" a "byte", porque hay que recordar que los valores de la función "PhraseToArray()" ya están en un valor numérico.
La función "IsLower()" no sufre ningún cambio.
Finalmente la función  FinalCipher() al igual que la función "CharToBaconianCode()" no sufre mayor cambio con respecto a la función de C#.
Y bien, por ahora es todo, cómo te habrás dado cuenta, todo funciona perfecto cuando vamos al derecho, pero no al revés, por absurdo que parezca, olvide escribir el código para realizar el proceso contrario, pero no te preocupes, en breve agregaré las partes faltantes en esta versión y en la versión de C#, además, la siguiente semana, la versión para android vendrá con la función para hacer el proceso inverso. Cómo siempre, la descarga del código la puedes hacer desde mi dropbox.

Por ahora es todo, los leo luego.

No hay comentarios. :

Publicar un comentario