Overblog Suivre ce blog
Administration Créer mon blog
26 mai 2012 6 26 /05 /mai /2012 13:55

Here is a common first year exercice question :

 

Write a function returning a random integer between 0 and n, n being passed as an argument to the function.

 

And here a common answer in C : 

 

 #include <stdlib.h>

// NB. don't forget to initialize with srand()

int random_integer(int n)
{
return (rand() / (RAND_MAX + 1.0) * (n+1));
}

This solution avoids the modulo operation on the value returned by rand() since it is likely to produce a non-uniform number distribution if RAND_MAX is not a multiple of n.

 

Anyway, the shiny new C++11 standard now comes with increased random number facilities located in the random header. Here is how to use them to produced the same result with them :

 

 #include <random> // clearer than stdlib, isn't it ? 

// NB. don't forget to initialize generator with its seed() method

int random_integer(std::mt19937& generator, int n)
{
std::uniform_int_distribution<int> dist_n(0, n);
return dist_n(generator);
}

Some remarks about this design :

  • C++11 standard provides several random number engines which are clearly identified by their names and their fomulas. Users can choose between them depending on their needs instead of trusting the rand() black box. In this example, I used the Mersenne Twister algorithm.
  • There is no shared global engine state like in C. With this design, each thread can have its own random number engine, which is better suited for multicore programming.
  • RNG engines are separated from distributions, which control the probability of a value to be a given range. Notable supported distributions are uniform (used in this article), normal (Gaussian), Poisson, etc.
  • Readability is way improved. Simply reading the dist_n variable declaration is far more understandable than the C equivalent formula.
Repost 0
Published by Olivier - dans Programmation
commenter cet article
21 mai 2012 1 21 /05 /mai /2012 18:25

Hi everyone, it's been a while !

 

One of the things that I apreciate in D is the way comparison operators overloading is implemented. Instead of having six individual operators to overload (<, <=, ==, !=, >= and >), you just have to implement a single special method called opCmp.

 

This opCmp method behaves exactly as memcmp or strcmp do in C :

  • It must return lesser than 0 if the first operand is lesser than the second.
  • It must return 0 for equality
  • It must return greater than 0 if the first operand is greater than the second.

While reading about template programming tricks, I stumbled across something called the Barton-Nackman trick, which is a special use of the Curiously Recurring Template Pattern.

 

So here is a simple trick to enable the overloading of the six comparison operators in C++ in one member function.

 

First of all, define a template class which has the overloads of the six operators which basically just interpret the return value of the opCmp method of its template parameter.

 

 template <class T>
class comparable
{
friend bool operator<(const T& t1, const T& t2)
{
return t1.opCmp(t2) < 0;
}
friend bool operator<=(const T& t1, const T& t2)
{
return t1.opCmp(t2) <= 0;
}
friend bool operator==(const T& t1, const T& t2)
{
return t1.opCmp(t2) == 0;
}
friend bool operator!=(const T& t1, const T& t2)
{
return t1.opCmp(t2) != 0;
}
friend bool operator>=(const T& t1, const T& t2)
{
return t1.opCmp(t2) >= 0;
}
friend bool operator>(const T& t1, const T& t2)
{
return t1.opCmp(t2) > 0;
}
};



Now, when you will need to implement all these operators at one for one of your types, you will just have to inherit privately from this class by using the CRTP and define an opCmp method in you class. Here is a simple example of such a thing :

 

 class number : private comparable<number>
{
int m_value;
public:
number(int n) : m_value(n)
{
}
int opCmp(const number& n) const
{
return m_value - n.m_value;
}
};

 

As you can see, only one method is now needed to implement all the 6 operators. Private inheritance is sufficient in this case and you be read is-implemented-using-a instead of the classical is-a relationship that is introduced by public inheritance. This is a good thing in terms of conception as it reduced dramatically the coupling and the dependencies between these two classes.

 

You'll find below a basic unit test of this number class :

 

 int main()
{
number three(3);
number three_again(3);
number two(2);
number five(5);
assert(three <= three_again);
assert(three == three_again);
assert(three >= three_again);
assert(two < three);
assert(two <= three);
assert(three > two);
assert(three >= two);
assert(three != two);
assert(two != three);
return EXIT_SUCCESS;
}
 
Repost 0
Published by Olivier - dans Programmation
commenter cet article
1 mai 2011 7 01 /05 /mai /2011 12:17

 

 

Hi, I am going to review the facilities provided by most object-oriented languages to add some methods to a type without subclassing nor accessing its inner implementation details. You can think of it as alternatives to the Adapter design pattern.

Let's say I have a type T and want to add a method to this type. For demonstration purposes, I will add a method called “universe” that will output the integer 42, which is, as Douglas Adams fans may know, the answer to life, universe and everything. Of course, in a real life program, one will add some more useful methods.

C#

 

C# provides something called “Extension methods”. These are simple public static methods in public static classes that take a first parameter with the this keyword.

 

 class T
{

// implementation of T...
}
public
static class Ext
{

public static int universe(this T t)
{
return 42;
}
}

 

Then one may call the universe method as if it was part of the T class :

 T t = new T();
int
i = t.universe();

One could notice that we get rid of any mention of the Ext class. It is only here because of the dotnet limitation that forbids global functions. Every method must belong to a class.

 

D

 

D provides a simple yet powerful mechanism called Uniform Function Call Syntax (UFCS). Basically, any function f(a[, ...]) can be rewritten as a.f([...]).

 

 class T
{
// implementation of T
}

int
universe(in T t) pure nothrow
{
return 42;
}

T t = new T;
t.universe();

 

This is much simpler than C# Extension methods and more powerful as it does not only applies to classes or structs, but also to built in types. Andrei Alexandrescu used them on built-in arrays to get them the Range interface he had defined for containers (see std.array and std.range D modules for more information).

Objective-C

 

Objective-C provides a way to add methods at runtime to an existing class without subclassing. This is called “categories”.

 

 @interface T : NSObject
{
// T fields
}
// T methods
@end
@implementation
T
// implementation of T methods
@end

// Add a new Category of T with a universe method
@interface
T (Universal)
- (int) universe;
@end

@implementation
T(Universal)
- (int) universe
{
return 42;
}
@end


// all the instances of T in the process now have a universe method
T* t = [[ T alloc] init];
int i = [ t universe ];

Python

 

Python being dynamic, it is very simple to add methods and fields to a class using the built in setattr function :

 

 class T:
pass

def
addUniverseToAClass(aClass):
def func(self):
return 42
setattr(aClass, "universe", func)

t = T()
addUniverseToAClass(T)
i = t.universe()

Java

  System.err.println(“I'm afraid I can't let you do that, Dave.”); // HA-HA ! 

 

Purpose

 

At this point, some of you may ask what is the point of doing all this ? These techniques can be very useful when doing some generic programming. Suppose you have written a very nice generic algorithm that works well with your types. And then someone provides you a new class that has similar abilities but a slightly different interface. Why would you subclass this new type ?

Inheriting a class creates a strong bind between a base class and its offspring that can later have consequences on the evolution of your code base. As you may have noticed, except Python, none of the programming languages presented here supports multiple inheritance...

Repost 0
Published by Olivier - dans Programmation
commenter cet article
17 mars 2011 4 17 /03 /mars /2011 20:29

J'ai finalement trouvé un emploi au sud-est de Toulouse, plus précisément à Labège.

Je travaille pour Acapela group, une société spécialisée dans la synthèse vocale. Vous pouvez trouver une démo interactive de leurs produits ici.

 

Tout ceci explique un peu l'inactivité de ce blog (honte à moi), je n'ai plus beaucoup de temps libre en ce moment, une installation demande pas mal de temps, entre les préparatifs toujours insuffisants, les démarches à faire après coup... J'espère arriver à sortir la tête de l'eau bientôt, après la période de rodage à ma nouvelle vie !

 

itinéraire

Repost 0
Published by Olivier - dans News
commenter cet article
17 janvier 2011 1 17 /01 /janvier /2011 13:53

 

 

Depuis la version 2.0 (Octobre 2000), le langage Python supporte les compréhensions de liste. Ce nom cache une syntaxe simple et concise pour créer de nouvelles listes à partir d'autres (en fait, tout objet itérable). C'est une fonctionnalité héritée des langages fonctionnels, ce qui explique que beaucoup de débutants venant de langages impératifs n'est pas le réflexe de les utiliser.

 

Cas d'exemple

 

Nous avons une liste d'entiers (peut importe son origine). Nous souhaitons filtrer cette liste et ne garder que les entiers dont le carré est supérieur à 50. En style impératif, on écrirait :

 nouvelleListe = list()
for entier in ancienneListe:
if entier ** 2 > 50:
nouvelleListe.append(entier)

 

Ces quatre lignes peuvent être simplifiées pour n'en faire qu'une seule au moyen d'une compréhension de liste :

 

 nouvelleListe = [ entier for entier in ancienneListe if entier ** 2 > 50 ]

 

Une compréhension de liste procède par filtrage pour créer une liste à partir d'une autre. La syntaxe est la suivante :

 

[ élémentÀAjouter for élément in séquence {if expression} ]

 

La première chose à remarquer est que l'expression créant une liste, elle est entourée de crochets [ et ], qui délimitent une liste littérale. Une compréhension de liste est divisée en trois parties. La première (ici appelée « élémentÀAjouter ») est simplement une expression qui sera ajoutée à la liste à chaque itération. La deuxième partie est identique à une boucle for classique. Pas de surprises ici. La troisième partie est optionnelle et permet de filtrer certains éléments. Dans le précédent exemple, on n'a retenu que les éléments dont le carré était supérieur à 50.

 

Intérêt des compréhension de listes

 

Outre leur concision, les compréhensions de listes améliorent la lisibilité d'un programme. Un coup d'oeil suffit à en reconnaître une et l'on sait immédiatement ce que l'on va faire. C'est un avantage indéniable pour un langage dynamique. L'exemple itératif demande de lire toute la boucle pour comprendre ce qu'elle fait. En outre, une compréhension de liste est beaucoup plus simple à appréhender que :

 

 nouvelleListe = list(filter(lambda x: x ** 2 > 50, ancienneListe)) 

 

Qui est complètement abscons pour beaucoup de développeurs alors qu'il fait la même chose.

 

Repost 0
Published by Olivier - dans Programmation
commenter cet article
5 décembre 2010 7 05 /12 /décembre /2010 09:58

En allant faire un tour au Marseille Startup Weekend hier (en touriste), j'ai rencontré un Américain fort sympathique prénommé Anthony. En discutant avec ce dernier à la pause déjeuner, j'ai pu découvrir un environnement de développement embarqué ouvert appelé Arduino.Arduino est destiné à des geeks hobbyistes créatifs qui souhaitent développer des prototypes d'objets ou de vêtements intelligents.

 

Une carte Arduino intègre généralement un microcontrôleur et peut recevoir une grande variété de senseurs, moteurs ou autre pour manipuler son environnement direct. La programmation se fait dans un langage dérivé du C qui est ensuite transformé en C avant d'être passé à avr-g++. La bibliothèque de fonctions est fournie sous licence LGPL.

 

Les kits Arduino sont fabriqué en Italie et sont complètement ouverts, tant sur le plan matériel que logiciel. Les schéma des composants sont disponibles et le kits de développement est open source. Le fabricant vend donc des solutions clés en mains qui pourraient autrement être assemblées par l'utilisateur lui-même en toute légalité.

 

Des kits complets sont disponibles à la vente pour un prix modique.

 

Plus d'informations sur http://www.arduino.cc/

Repost 0
Published by Olivier - dans Bidouille
commenter cet article
25 novembre 2010 4 25 /11 /novembre /2010 11:58

Sony starts an experimental R&D project to leverage the open source community to build and evolve the next generation application framework for consumer electronic devices. The project is called SNAP (Sony Network Application Platform). I am far from being a Sony fanboy, the reason why I talk about it here that it is a fork of the GNUStep framework.

 

To understand what GNUStep is, let's do like Doc and Marty and go back in time to 1985. Steve Jobs was fired from Apple and started a new IT company called NeXT. NeXT produced high-end computer workstations based on their own UNIX-based operating system called NeXTStep. Like the mac, NeXTStep was a graphical operating system with strong human-machine interface guidelines. But what differentiated NeXTStep from other OSes at the time was its strong reliance on the Objected-Oriented paradigm. The NextStep APIs particularly well designed and were written in a strange dynamic flavor of the C language called “Objective-C”.

Those of you familiar with Mac OS X might have a feeling of déjà-vu. Well, Apple will buy NeXT in 1997 and what you get on your Mac since 2001 is nothing but the evolution of NeXTStep with a Mac skin.

What is important to know is that before being bought, NeXT did release a complete public specification of the NeXTStep APIs called OpenStep, with the help of Sun Microsystems. OpenStep was used by NeXTStep and Solaris. GNUStep is a GNU project that provides a free implementation of the OpenStep specs.

 

After the NeXT acquisition by Apple, APIs did continue to evolve under a new fancy name, “Cocoa”. While Sun stopped OpenStep in Solaris, GNUStep didn't and strongly adheres to the original specs.

So let's see what the purpose of SNAP is. According to Sony, SNAP goal is not to provide a strong compatibility to OpenStep. Indeed, they claim to modernize the framework and optimize it to modern consumer electronic devices.This is what Apple did with the iPhone (based on a variant of Cocoa called Cocoa Touch). The SNAP development environment is based on Ubuntu Linux and has reached beta stage. Sony recommends to install it in a virtual machine by now. If it is successful, programming on future Sony devices may feel a bit like programming on the iPhone.

Repost 0
Published by Olivier - dans News
commenter cet article
8 novembre 2010 1 08 /11 /novembre /2010 10:59

« Le compte est bon » est un célèbre jeu télévisé, d'abord autonome, puis intégré à l'émission « Des chiffres et de lettres ». Le principe est simple, on tire au hasard un nombre entre 101 et 999. Deux candidats devront aboutir à ce résultat d'après six nombres tirés au hasard parmi la liste suivante : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 25, 50, 75 et 100 en utilisant les quatre opérations arithmétiques de base. Nous allons voir ensemble comment réaliser une application permettant de trouver une solution à ce jeu en langage Python.

 

Données utilisables

Chaque opération possible (addition, multiplication, soustraction et division) est une opération binaire. C'est-à-dire qu'elle fait intervenir deux opérandes. À partir de notre liste de 6 entiers, on va former des paires sur lesquelles on effectuera les opérations. On n'a le droit d'utiliser chaque nombre qu'une fois, mais on peut réutiliser le résultat d'une opération précédente. Donc à chaque fois qu'on fait une opération, on « perd » les deux opérandes, et on « gagne » le résultat de l'opération.

 

On voit ainsi se dessiner l'esquisse d'un algorithme récursif de type backtracking.

 

Capture d’écran 2010-11-08 à 11.04.19

Réduisons l'espace de recherche

Prenons deux nombres A et B au hasard. On peut remarquer plusieurs choses :

  • L'addition est commutative. C'est-à-dire que A + B et B +A donneront toujours le même résultat. Il en est de même pour la multiplication. Il est donc inutile de faire la deuxième opération si on a déjà fait la première.

  • Si A = B, la soustraction donnera 0. Faire rentrer 0 dans nos données donnera des calculs ultérieurs inutiles ou interdits. On peut donc éviter ce calcul :

    • A + 0 = A (inutile)

    • A x 0 = 0 (inutile)

    • A : 0 est interdit

  • Si A < B, la soustraction donnera un entier négatif (on sort de l'espace de solutions) et la division entière donnera 0. Ce sont donc également des calculs inutiles.

 

Ces constatations nous amènent à ne faire que les opérations pour A >= B, et à éviter la soustraction si A = B. On réduit donc de plus de moitié notre espace de recherche, gagnant ainsi un temps précieux !

 

Générateur de paires d'entiers

Nos quatre opérations étant binaires, nous devons, à partir d'une liste d'entiers, générer toutes les paires d'opérandes possibles. Cela est facilement réalisable en utilisant une liste triée par ordre décroissant. Il suffit de maintenir deux index sur cette liste. On déplace un index à chaque accès et un autre chaque fois que le premier sort des limites de la liste. On s'arrête lorsque l'on ne peut plus rien déplacer.

 

Journal des opérations

Afin de pouvoir afficher les étapes du calcul lorsque l'on a trouvé une solution, on utilise une liste de chaînes de caractères. Après chaque opération, on note celle-ci dans la liste. Si un nœud de l'arbre d'exploration n'a donné aucun résultat, on l'enlève de la liste.

 

Code source de notre programme

 #!/usr/bin/python



import sys



# Les quatre fonctions arithmetiques de base

add = lambda x, y: x + y

sub = lambda x, y: x - y

mul = lambda x, y: x * y

div = lambda x, y: x // y



class Operation:

"""

Classe associant une operation a sa description textuelle, pour pouvoir

afficher le detail des calculs effectues lorsqu'on a trouve le resultat.

"""

def __init__(self, func, desc):

"""

Constructeur : initialise les deux champs

func : pointeur vers la function qui fait le calcul

desc : chaine de caractere, descriptif

"""

self.func = func

self.desc = desc



# Les quatre operations

ALL_OPERATIONS = (Operation(add, "+"), Operation(sub, "-"),

Operation(mul, "x"), Operation(div, ":"))



# Les operations qui ne peuvent pas donner 0 comme resultat

OPERATIONS = (Operation(add, "+"), Operation(mul, "x"),

Operation(div, ":"))



#----------------------------------------------------------------------------



class PairIterator:

"""

Classe donnant une suite de paire de nombres a partir d'une liste de

nombres.



"""

def __init__(self, nums):

assert len(nums) >= 2, "La liste doit contenir au moins 2 elements"

self.nums = nums

self.index1 = 0

self.index2 = 1



def __iter__(self):

""" La classe est son propre iterateur. """

return self



def __next__(self):

""" Renvoie la prochaine paire d'entiers """

# Si on est arrive au bout de la liste de paires

if self.index2 == len(self.nums):

raise StopIteration

# Cree une paire

p = (self.nums[self.index1], self.nums[self.index2])



# Avance la position pour la prochaine fois

if self.index2 < len(self.nums) - 1:

self.index2 += 1

else:

self.index1 += 1

self.index2 = self.index1 + 1



return p



def next(self):

"""

Meme fonction que la precedente, par souci de compatibilite

avec python 2.x

"""

return self.__next__()

#----------------------------------------------------------------------------



def algo(entiers, aTrouver, log=[]):

"""

Fonction de recherche de solutions.



Parametres:

entiers: liste de donnees utilisables (entiers)

aTrouver: resultat auquel aboutir (entier)

log: liste des operations deja effectuees (liste de chaines)

"""

assert len(entiers) >= 2, "La liste doit contenir au moins 2 elements"



# Pour chaque paire d'entiers

paires = PairIterator(entiers)

for paire in paires:

# On evite de faire des calculs qui donnent 0 comme resultat

ops = OPERATIONS if paire[0] == paire[1] else ALL_OPERATIONS

for op in ops:

# On fait le calcul

resultat = op.func(paire[0], paire[1])

# Note l'operation dans le journal

log.append("%d %s %d = %d" % (paire[0], op.desc, paire[1],

resultat))



# Si on a trouve la solution

if resultat == aTrouver:

# On affiche les operations effectuees et on quitte

for ligne in log:

print(ligne)

sys.exit(0)

else:

# On prend les autres nombres et le resultat de l'operation

entiers2 = [n for n in entiers if n not in paire]

entiers2.append(resultat)

# et on recommence

entiers2.sort(reverse = True)

if len(entiers2) >= 2:

algo(entiers2, aTrouver, log)

# L'operation n'a pas donne de resultat, on l'enleve du journal

log.pop()



#----------------------------------------------------------------------------



VALIDES = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 25, 50, 75, 100)



if len(sys.argv) != 8:

print("Pas assez d'arguments.")

print("usage : compte nb1 nb2 nb3 nb4 nb5 nb6 aTrouver")

sys.exit(1)

else:

try:

entiers = [ int(i) for i in sys.argv[1:7] ]

aTrouver = int(sys.argv[-1])

except:

print("Les arguments de ce programmes doivent etre des entiers")

sys.exit(2)



# Verifie que le nombre a trouver est valide

if aTrouver <= 100 or aTrouver >=1000:

print("Argument invalide")

print("Le nombre a trouver doit etre compris entre 101 et 999")

sys.exit(3)



# Verifie que tous les nombres sont dans la liste des valides

if any(e not in VALIDES for e in entiers):

print("Argument(s) invalide(s)")

print(("Les nombres doivent etre dans la liste %s" % (str(VALIDES))))

sys.exit(3)



entiers.sort(reverse = True)

algo(entiers, aTrouver)

print ("Aucun resultat.")

Repost 0
Published by Olivier - dans Programmation
commenter cet article
29 octobre 2010 5 29 /10 /octobre /2010 11:48

 

Ayant égaré mon accordeur, je me suis lancé dans la réalisation d'un équivalent logiciel. J'ai une première version fonctionnelle au bout d'une journée de travail. N'ayant pas d'adaptateur pour brancher mon instrument sur mon ordinateur (on ne se moque pas), j'ai mis de côté l'idée de réaliser un accordeur à reconnaissance de fréquence, pour me rabattre – provisoirement – sur un générateur sonore. En gros l'équivalent numérique d'un de ces vieux accordeurs à sifflets de grand-papa, ce qui aura l'avantage de faire travailler l'oreille :

 

accordeur01

 

J'ai prévu l'utilisation d'une bibliothèque d'accordages la plus complète possible. Nos amis guitaristes étant très inventifs à ce niveau-là, celle-ci est extensible.

 

accordeur

Génération du son

 

Le framework .net « out-of-the-box » n'étant pas très riche en fonctionnalités multimédias, j'ai décidé de faire appel au composant dédié au son de DirectX, j'ai nommé DirectSound. Il existe un excellent binding open source pour accéder à DirectX depuis .net, SlimDX. La génération du son se fait en réservant un tampon dans la mémoire de la carte son et en écrivant un signal sinusoïdal de la bonne fréquence dans celui-ci.

 

 SecondarySoundBuffer buffer = new SecondarySoundBuffer(directSound, desc2);

short[] data = new short[44100 * 8];
double angle = 0.0;
for (int i = 0; i < data.Length; ++i)
{
data[i] = (short)(32767 * System.Math.Sin(angle));
angle += 2 * System.Math.PI * freq / 44100;
if (angle > 2 * System.Math.PI)
{
angle -= 2 * System.Math.PI;
}
}
buffer.Write<short>(data, 0, LockFlags.None);
buffer.Play(0, PlayFlags.None);

 

Calcul de la fréquence d'une note de musique

 

Pour trouver la fréquence à utiliser pour chaque note de musique, un petit calcul s'impose. La note de référence internationalement admise est le LA 5e octave à 440Hz*.

Sachant que la fréquence d'une note double lorsqu'on monte d'une octave, et qu'une octave est divisée en 12 demi-tons égaux**, on en déduit facilement la formule de calcul de la fréquence :

 

F = A * pow(pow(2, 1.0 / 12.0), n)

 

Où A est la fréquence de la note de référence (ici 440) et n le nombre de demi-tons qui séparent la note courante de la note de référence.

 

* : Certains musiciens (comme Francis Darizcuren) aiment prendre une note de référence un peu plus haute, comme 442Hz afin de rajouter un peu de brillance au son. C'est une fonctionnalité que je prévois d'implémenter dans une future version.

** : Une guitare utilise un tempérament modéré, on ne fait donc pas de distinction entre les demi-tons chromatiques et les demi-tons diatoniques.

Repost 0
Published by Olivier - dans Projets personnels
commenter cet article
21 octobre 2010 4 21 /10 /octobre /2010 12:10

 

I realized that I've been spending much time lately speaking about programming languages and stuff like that, I want to take a small break with these things and talk a little more about things that might interest the average Joe. As I spent some days in London last week, I guess I will do it in English. Most of my posts are in French because it is the language I'm the most familiar with, but I'll make an effort this time to try to target a larger audience.



I have been playing the bass guitar for 10 years by now. Of course there were times when I used to be able to play more than nowadays, but it is still something big for me. This post gives me the opportunity to start a new category of articles oriented toward music, the kind of music I listen to, the kind of music I play, et cætera. Today I am going to talk about the basses I own, and particularly the two that I actually do play.



2004 4-string MusicMan SUB

I got this this one in January 2004. The SUB series are now discontinued, but at the time it was among the first models to be shipped in France I think. The SUBs came in different flavors : active or passive, 4 and 5 strings. This one is active. They were modeled after the Stingray, sharing the same electronics. The cost of the instrument was mainly cut down from a much less draconian selection of woods. This is probably the reason why every part of the instrument was painted, not showing the wood under it and why no maple fingerboard option was available. The wood might be ugly under the paint, but anyway, it sounds good.

 

basses 1748

 

The body is in poplar. Poplar is often used as a low-cost replacement for alder. The aluminum pickguard gives the instrument a industrial look. I would have preferred a simple white plastic one, but I find it OK. Like the Stingray, there is only one humbucking pickup. The controls are simple: volume, bass boost/cut and treble boost/cut. One might find it too limited, but I don't like spending too much time setting up my sound. I prefer instruments that have a strong personality, with a sound easily recognizable, like this bass. You just just have to grab it and plug it in your amp, and you have the Musicman sound.

 

basses 1749

 

Here is a pic of the neck and the fretboard. As often, the neck is in maple and the fretboard is in rosewood. I never owned a bass having a different kind of wood for fretboard, so sometimes I feel like I might be missing something. The neck is kind of thick, as it is on a Fender Precision or a MusicMan Stingray. I started playing on a cheap copy of Precision and I am used to thick necks. The gap between strings makes slap easy. The neck is 21 frets long.

 

basses 1750

 

Here is a pic of the back of the body. The black box holds the 9V battery and is just perfect. It opens by clips, so changing the battery is really easy: you don't have to use a screwdriver or any tool. The neck/body junction is performed with 6 screws.

 

basses 1751

 

Here is a pic of the back of the head, showing the keys, the serial number and the country in it was manufactured (USA). The bass came naked, without any accessory : no jack, no bag, no case, nothing !

2007 6-string Ibanez SR-1006

I ordered this one at Thomann in December 2007 (and received it in Feb 2008). I wanted a complement to my Musicman, so this bass is everything the Musicman is not. The SR (SoundgeaR) is one of the most successful series from Ibanez since it was introduced in the late 80s. The SR-1000 was the high-end line at the time. The purpose of the SR is to offer a thin 24-fret neck and a versatile, modern-sounding instrument. I can confirm the versatility of this bass. You can play any style with it from gospel to death metal, as long as you like modern sound. For those of you who might not know about 6-string basses, their empty string notes differ from guitar. From the low to the high, the notes are B-E-A-D-G-C, while they are E-A-D-G-B-E on a 6-string guitar.

 

basses 1752

 

Here is the body. The two pickup are from Bartolini. The 6 ( ! ) controls are volume, balance, bass boost/cut, treble boost/cut, medium freq selection and medium boost/cut. The saddles are independent. When turning the controls, you will feel a stop when you are at mid-range, which is just brilliant for knowing that balance is equal on the two pickups, for example. As I said, I am not the kind of guy who will spend hours setting his sound, so what I usually do is writing down sound settings when I find something I like to switch back to it easily later.

 

basses 1753

 

Here is a pic of the neck and the fretboard. The neck is body-through. It means there is no separation between the neck and the body. They are only one piece of wood. Crafting is much better on this bass than on the Musicman. The consequence is a much longer sustain. Hit a note and it will sound as it'll last forever ! Sustain is the main problem of the Musicman, so I'm very happy this bass doesn't share the same problem.

 

basses 1754

 

Here is the back of the body. It is a pity the 9V battery is accessible by removing 2 screws. For the price range of the instrument (€1300 - €1600), one could reasonably expect the same kind of box as on the Musicman. You can also see the body-neck junction. It makes hitting high notes very easy (for what it's worth on a bass). The neck is reinforced using two carbon rods that are hidden under the brown lines.

 

basses 1755

 

Here is a pic of the back of the head, showing the keys, the serial number and the country in it was manufactured (Korea). The bass came in it's Ibanez prestige case, with a (bad) jack, a whole set of Allen keys, some picks, a strap and 6-language instruction manual ! Musicman should learn from Ibanez !

Repost 0
Published by Olivier - dans musique
commenter cet article

Présentation

Recherche

Liens