Zakładając że zawartość pliku wygląda tak:
123456789012345678901234567890
chodzi mi o uzyskanie wynikowego pliku o zawartości:
Przy czym sekwencja powyżej przykładowo podana jako "1234567890" nie jest mi znana, a w zależności od pliku jej długość będzie wynosić od kilkuset bajtów do kilku MB
Pliki są w jednym folderze i mają rozszerzenie wav, ale domyślam się że trzeba będzie je przekonwertować do raw przed rozpoczęciem wyszukiwania. Każda sekwencja jest unikalna dla danego pliku dlatego trzeba ją wykryć.
Możesz pobawić się w napisanie skryptu w bash
1. Konwertujesz kazdy plik .wav do hex
2. I porównujesz jakimś bardziej inteligentnym diffem lub algorytmem.
Przykłady masz tutaj jak porównać dwa pliki binarne na różne sposoby
http://superuser.com/questions/125376/how-do-i-compare-binary-files-in-linux
Kurs basha
http://dief.republika.pl/main.html
# a = Lista plików wav
a=$(ls twoja_sciezka_do_katalogu | grep ".wav" )
b=$(ls twoja_sciezka_do_katalogu | grep ".wav" | wc -l)
# Policzy pliki wav
echo "Plików jest $b"
# petla for wykona sie tyle ile jest
# razem plików
for i in `seq 1 $b`
do
# linia
echo "$i"
# nazwa pliku
d=$(awk 'NR=='$i <<< "$a")
for i in `seq 1 $b`
do
# nazwa pliku
c=$(awk 'NR=='$i <<< "$a")
echo "Porównaj: $d - $c"
done
done
Otrzymasz coś takiego
./test
Plików jest 5
1
Porównaj: plik1 (1. kopia).wav - plik1 (1. kopia).wav
Porównaj: plik1 (1. kopia).wav - plik1 (2. kopia).wav
Porównaj: plik1 (1. kopia).wav - plik1 (3. kopia).wav
Porównaj: plik1 (1. kopia).wav - plik1 (4. kopia).wav
Porównaj: plik1 (1. kopia).wav - plik1.wav
2
Porównaj: plik1 (2. kopia).wav - plik1 (1. kopia).wav
Porównaj: plik1 (2. kopia).wav - plik1 (2. kopia).wav
Porównaj: plik1 (2. kopia).wav - plik1 (3. kopia).wav
Porównaj: plik1 (2. kopia).wav - plik1 (4. kopia).wav
Porównaj: plik1 (2. kopia).wav - plik1.wav
3
Porównaj: plik1 (3. kopia).wav - plik1 (1. kopia).wav
Porównaj: plik1 (3. kopia).wav - plik1 (2. kopia).wav
Porównaj: plik1 (3. kopia).wav - plik1 (3. kopia).wav
Porównaj: plik1 (3. kopia).wav - plik1 (4. kopia).wav
Porównaj: plik1 (3. kopia).wav - plik1.wav
4
Porównaj: plik1 (4. kopia).wav - plik1 (1. kopia).wav
Porównaj: plik1 (4. kopia).wav - plik1 (2. kopia).wav
Porównaj: plik1 (4. kopia).wav - plik1 (3. kopia).wav
Porównaj: plik1 (4. kopia).wav - plik1 (4. kopia).wav
Porównaj: plik1 (4. kopia).wav - plik1.wav
5
Porównaj: plik1.wav - plik1 (1. kopia).wav
Porównaj: plik1.wav - plik1 (2. kopia).wav
Porównaj: plik1.wav - plik1 (3. kopia).wav
Porównaj: plik1.wav - plik1 (4. kopia).wav
Porównaj: plik1.wav - plik1.wav
Oczywiście musisz zamiast echo "Porównaj: $d - $c" musisz podać własną komendę (komendy) lub algorytm do porównania który Ci najbardziej będzie odpowiadał,
lub nawet jeśli chcesz zmienić pętle z for na while.
Kombinuj, a napewno coś wymyślisz.
Czy długość bloku jest znana?
Założę, że nie, choć oczywiście musi być określona (sensowna) długość minimalna.
Jak rozumiem powtórzeń szukamy tylko w ramach danego pliku? A nie we wszystkich?
Program na szybko, ale wygląda, że działa:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MIN_BLOCK_LENGTH 5
int main(int argc, char** argv) {
if (argc < 2) {
printf("Usage:\n %s filename\n", argv[0]);
return 1;
}
FILE *f = fopen(argv[1], "rb");
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
char *content = malloc(size + 1);
fread(content, size, 1, f); // assume we can fit the file in the memory
fclose(f);
int i = 0; // origin index
while (i < size - 2 * MIN_BLOCK_LENGTH) {
int s = i + MIN_BLOCK_LENGTH; // search index
while (s < size - MIN_BLOCK_LENGTH) {
if (memcmp(content + i, content + s, MIN_BLOCK_LENGTH) == 0) {
// we have at least minimum length match
int length = MIN_BLOCK_LENGTH + 1;
// check if the match is longer than the minimum
while (i + length <= s && s + length <= size) {
if(memcmp(content + i, content + s, length) != 0) {
break;
}
length++;
}
length--; // the loop above ended with a valid value plus one
// print data for the found repetition and the string itself
printf("Found %d bytes long repetition"
" starting byte %d at byte %d:\n",
length, i + 1, s + 1);
printf("%.*s\n", length, content + i);
// skip origin index after the found repetition
i = i + length - 1; // will ++ soon in the outer loop
break;
}
s++; // next search index
}
i++; // next origin index
}
free(content);
return 0;
}
Kompilacja:
Odpalanie:
Przykładowy plik na wejściu:
abc1234567890123xyz1234567890123AAAAA111qwerty1234567890123qwerty000abc000AAAAABBBBBBBBBBB
Wyjście:
Found 13 bytes long repetition starting byte 4 at byte 20:
1234567890123
Found 13 bytes long repetition starting byte 20 at byte 47:
1234567890123
Found 5 bytes long repetition starting byte 33 at byte 75:
AAAAA
Found 6 bytes long repetition starting byte 41 at byte 60:
qwerty
Found 5 bytes long repetition starting byte 80 at byte 85:
BBBBB
Jak możesz, to wrzuć jeden przykładowy plik.
Dzięki za wskazówki, niestety niewiele z nich rozumiem :-[ i sam sobie takiego programu na pewno nie napiszę, ale jeśli komuś temat wydaje się ciekawy to zapraszam do zmierzenia się z nim :). A może i inni skorzystają z wyniku tego wyzwania?
O_O` Takie coś jest do działu "Bazar/Kupię"
Pliki są generowane, a ze specyfikacji teoretycznie wynika że sekwencja powinna być idealnie powtarzalna.
Przykładowy plik: 2A03_N_Long_vF_D.wav] (https://dl.dropboxusercontent.com/u/569546/tmp/2A03_N_Long_vF_D.wav)
Ewentualnie inna opcja - może ktoś na bazie tych tajemniczych cyferek potrafi wyliczyć długość sekwencji? ΦωΦ)
http://wiki.nesdev.com/w/index.php/APU_Noise
Dałeś opis generatora dźwięku w procesorze konsoli NES. W jaki sposób znalazł się on w pliku WAV? No, ale dobrze:
Po analizie autokorelacyjnej pliku wyszło, że powtarzalność nie jest dokładna:
import scipy.io.wavfile as wf
import matplotlib.pyplot as plt
import numpy as np
# Wczytanie pliku
frq, sound = wf.read("dane.wav")
# Normalizacja na zakres -1.0 .. 1.0
sound = sound / 32768.0
# Ile sampli wycinamy (całość się wolno liczy)
fragment = 400000
# Odkomentuj, jeżeli jendak chcesz liczyć dla całości
# fragment = len(sound)
# Liczymy autokorelację fragmentu
ac = np.correlate(sound[:fragment], sound[:fragment], mode="same")
# Autokorelacja sam ze sobą bez przesunięcia jest w połowie,
# Na lewo i prawo masz przesunięcia w lewo i prawo względem oryginału
# Obraz jest symetryczny, bo to jest autokorealcja, dlatego wycinamy tylko
# "górną" połówkę
acr = ac[fragment // 2:]
# Maksimum jest gdzieś koło 28k
base = 28000
# Szukamy w zakresie base-rang .. base+rang
rang = 2000
# Analiza dla kolejnych harmonicznych:
for harm in range(1, 1 + (len(acr) - rang) // base):
maxy = -1000.0
maxx = 0
for x in range(harm * base - rang, harm * base + rang):
if acr[x] > maxy:
maxy = acr[x]
maxx = x
print(
"Harmoniczna %d: Największa korelacja jest dla okresu %d sampli 2-bajtowych (%f)" % (
harm, maxx / harm, maxy))
# Oś X to przesunięcie kopii i oryginału
x = np.arange(len(acr))
# Rysujemy wykres autokorelacji. Kolejne "piki" opowiadają okresom.
# Piki mają malejącą wysokość, więc dane NIE SĄ IDEALNIE POWTARZALNE
# i szukanie po bajtach nie ma sensu.
plt.plot(x, acr)
plt.show()
Dla Twojego pliku wychodzi "pseudookres" 28119 sampli (56238 bajtów)
Tu jest program sam wyszukujący pików (poprzedni mógł pokazywać bzdury jak się żle dobrało base i rang)
import scipy.io.wavfile as wf
import matplotlib.pyplot as plt
import numpy as np
# Wczytanie pliku
frq, sound = wf.read("dane.wav")
# Normalizacja na zakres -1.0 .. 1.0
sound = sound / 32768.0
# Ile sampli wycinamy (całość się wolno liczy)
fragment = 400000
# Odkomentuj, jeżeli jendak chcesz liczyć dla całości
# fragment = len(sound)
# Liczymy autokorelację fragmentu
ac = np.correlate(sound[:fragment], sound[:fragment], mode="same")
# Autokorelacja sam ze sobą bez przesunięcia jest w połowie,
# Na lewo i prawo masz przesunięcia w lewo i prawo względem oryginału
# Obraz jest symetryczny, bo to jest autokorealcja, dlatego wycinamy tylko
# "górną" połówkę
acr = ac[fragment // 2:]
harm = 0
level = acr[0] / 10
# Szukamy końca 1. piku
# End of peak 1
eop1 = 0
for x in range(0, len(acr)):
if acr[x] < level:
# Pierwszy pik kończy się po spadnięciu poziomu do 10%
eop1 = x
break
maxy = 0.0
maxx = 0
# Numer peaku
peak = 1
# 0 - jesteśmy w piku
# 1 - jesteśmy między pikami
state = 1
maxy = 0.0
maxx = 0
for x in range(eop1, len(acr)):
if state == 1:
# Między pikami - szukamy początku piku
if acr[x] > 2 * level:
state = 0
maxy = 0.0
maxx = 0
harm += 1
else:
# W piku - szukamy makymalnej wartości
if acr[x] > maxy:
maxy = acr[x]
maxx = x
# Szukamy końca piku
if acr[x] < level:
state = 1
print(
"Harmoniczna %d: Największa korelacja jest dla okresu %d sampli 2-bajtowych" % (
harm, maxx // harm))
# Dostrajamy poziom
level = maxy / 10
# Oś X to przesunięcie kopii i oryginału
x = np.arange(len(acr))
# Rysujemy wykres autokorelacji. Kolejne "piki" opowiadają okresom.
# Piki mają malejącą wysokość, więc dane NIE SĄ IDEALNIE POWTARZALNE
# i szukanie po bajtach nie ma sensu.
plt.plot(x, acr)
plt.show()